diff -r b647ecaa2068 cnd.api.model/src/org/netbeans/modules/cnd/api/model/CsmFile.java --- a/cnd.api.model/src/org/netbeans/modules/cnd/api/model/CsmFile.java Fri Sep 11 17:03:04 2015 +0300 +++ b/cnd.api.model/src/org/netbeans/modules/cnd/api/model/CsmFile.java Wed Sep 16 20:03:55 2015 +0300 @@ -51,6 +51,12 @@ * @author Vladimir Kvashin */ public interface CsmFile extends CsmNamedElement, CsmScope, CsmValidable { + + /** Adds the property to this file */ + void putProperty(Object key, Object value); + + /** Gets the property associated with this file */ + Object getProperty(Object key); /** Gets this file normalized absolute path */ CharSequence getAbsolutePath(); diff -r b647ecaa2068 cnd.completion/src/org/netbeans/modules/cnd/completion/cplusplus/CsmCompletionUtils.java --- a/cnd.completion/src/org/netbeans/modules/cnd/completion/cplusplus/CsmCompletionUtils.java Fri Sep 11 17:03:04 2015 +0300 +++ b/cnd.completion/src/org/netbeans/modules/cnd/completion/cplusplus/CsmCompletionUtils.java Wed Sep 16 20:03:55 2015 +0300 @@ -78,7 +78,7 @@ * @see NbEditorDocument#MIME_TYPE_PROP */ public static String getMimeType(Document doc) { - return DocumentUtilities.getMimeType(doc); + return doc != null ? DocumentUtilities.getMimeType(doc) : null; } /** @@ -116,6 +116,9 @@ } public static boolean isNaturalSort(String mimeType) { + if (mimeType == null || mimeType.length() == 0) { + return false; + } Preferences prefs = MimeLookup.getLookup(mimeType).lookup(Preferences.class); return prefs.getBoolean(SimpleValueNames.COMPLETION_NATURAL_SORT, false); } diff -r b647ecaa2068 cnd.completion/src/org/netbeans/modules/cnd/completion/cplusplus/ext/CompletionSupport.java --- a/cnd.completion/src/org/netbeans/modules/cnd/completion/cplusplus/ext/CompletionSupport.java Fri Sep 11 17:03:04 2015 +0300 +++ b/cnd.completion/src/org/netbeans/modules/cnd/completion/cplusplus/ext/CompletionSupport.java Wed Sep 16 20:03:55 2015 +0300 @@ -129,16 +129,27 @@ public final class CompletionSupport implements DocumentListener { private final Reference docRef; + private final Reference fileRef; // not for external instantiation + public CompletionSupport(CsmFile file) { + docRef = new WeakReference(null); + fileRef = new WeakReference(file); + } + private CompletionSupport(Document doc) { docRef = new WeakReference(doc); + fileRef = new WeakReference(null); doc.addDocumentListener(this); } public static CompletionSupport get(JTextComponent component) { return get(component.getDocument()); } + + public static CompletionSupport get(final Document doc, final CsmFile file) { + return (doc != null) ? get(doc) : get(file); + } public static CompletionSupport get(final Document doc) { CompletionSupport support = (CompletionSupport) doc.getProperty(CompletionSupport.class); @@ -158,10 +169,19 @@ } return support; } + + public static CompletionSupport get(final CsmFile file) { + // no cache for now + return new CompletionSupport(file); + } public final Document getDocument() { return this.docRef.get(); } + + public final CsmFile getFile() { + return this.fileRef.get(); + } public static boolean isPreprocCompletionEnabled(Document doc, int offset) { return isIncludeCompletionEnabled(doc, offset) || isPreprocessorDirectiveCompletionEnabled(doc, offset); @@ -251,7 +271,11 @@ public int doc2context(int docPos) { int offset = this.contextOffset == NOT_INITIALIZED ? docPos : this.contextOffset; - offset = CsmMacroExpansion.getOffsetInOriginalText(getDocument(), offset); + if (getDocument() != null) { + offset = CsmMacroExpansion.getOffsetInOriginalText(getDocument(), offset); + } else { + offset = CsmMacroExpansion.getOffsetInOriginalText(getFile(), offset); + } return offset; } diff -r b647ecaa2068 cnd.completion/src/org/netbeans/modules/cnd/completion/cplusplus/ext/CsmCompletionQuery.java --- a/cnd.completion/src/org/netbeans/modules/cnd/completion/cplusplus/ext/CsmCompletionQuery.java Fri Sep 11 17:03:04 2015 +0300 +++ b/cnd.completion/src/org/netbeans/modules/cnd/completion/cplusplus/ext/CsmCompletionQuery.java Wed Sep 16 20:03:55 2015 +0300 @@ -354,14 +354,10 @@ if (enterThreadLocalAntiloop(AntiloopClient.query_type, expression)) { try { CsmCacheManager.enter(); + + // Note that baseDocument can be null baseDocument = (BaseDocument) CsmUtilities.getDocument(expression.getContainingFile()); - if (baseDocument == null) { - CloneableEditorSupport support = CsmUtilities.findCloneableEditorSupport(expression.getContainingFile()); - if (support == null) { - return false; - } - baseDocument = (BaseDocument) support.openDocument(); - } + assert getBaseDocument() != null || getCsmFile() != null : "Either document or CsmFile must be provided!"; // NOI18N final int startOffset = expression.getStartOffset(); final int endOffset = expression.getEndOffset(); @@ -370,8 +366,6 @@ // return false; // } - long docVersion = DocumentUtilities.getDocumentVersion(baseDocument); - // TokenProcessorCache property = (TokenProcessorCache) baseDocument.getProperty(TOKEN_PROCESSOR_CACHE_KEY); // CsmCompletionTokenProcessor tp = null; // if (property != null) { @@ -385,14 +379,13 @@ } CsmCompletionTokenProcessor tp; - CsmScope passedScope = null; if (CsmKindUtilities.isExpression(expression)) { passedScope = ((CsmExpression) expression).getScope(); tp = processTokensInExpression((CsmExpression) expression, task.isFindTypeTask()); } else { - tp = processTokensInFile(csmFile, startOffset, endOffset, baseDocument, docVersion); + tp = processTokensInFile(csmFile, startOffset, endOffset, baseDocument); } if (!checkErrorTokenState(tp)) { @@ -429,8 +422,6 @@ } else if (TRACE_COMPLETION) { System.err.println("Error expression " + tp.getResultExp()); } - } catch (IOException ex) { - ex.printStackTrace(System.err); } finally { exitThreadLocalAntiloop(AntiloopClient.query_type, expression); CsmCacheManager.leave(); @@ -561,7 +552,7 @@ if (tp == null) { // find last separator position final int lastSepOffset = sup.getLastCommandSeparator(csmFile, offset, getFileReferencesContext()); - tp = processTokensInFile(csmFile, lastSepOffset, offset, doc, docVersion); + tp = processTokensInFile(csmFile, lastSepOffset, offset, doc); baseDocument.putProperty(TOKEN_PROCESSOR_CACHE_KEY, new TokenProcessorCache(offset, docVersion, tp)); } else { // hit @@ -719,7 +710,7 @@ return errState; } - private CsmCompletionTokenProcessor processTokensInFile(CsmFile csmFile, final int startOffset, final int endOffset, final BaseDocument doc, final long docVersion) { + private CsmCompletionTokenProcessor processTokensInFile(CsmFile csmFile, final int startOffset, final int endOffset, final BaseDocument doc) { CsmCompletionTokenProcessor tp = new CsmCompletionTokenProcessor(endOffset, startOffset); final CndTokenProcessor> etp = CsmExpandedTokenProcessor.create(csmFile, doc, tp, endOffset); if(etp instanceof CsmExpandedTokenProcessor) { @@ -727,12 +718,19 @@ } tp.enableLambdaSupport(areLambdasEnabled(csmFile)); tp.enableTemplateSupport(areTemplatesEnabled(csmFile)); - doc.render(new Runnable() { - @Override - public void run() { - CndTokenUtilities.processTokens(etp, doc, startOffset, endOffset); + if (doc != null) { + doc.render(new Runnable() { + @Override + public void run() { + CndTokenUtilities.processTokens(etp, doc, startOffset, endOffset); + } + }); + } else { + TokenSequence cppTokenSequence = CsmFileInfoQuery.getDefault().getCppTokenSequence(csmFile, startOffset, false, endOffset < startOffset); + if (cppTokenSequence != null) { + CndTokenUtilities.processTokens(etp, cppTokenSequence, startOffset, endOffset); } - }); + } return tp; } @@ -748,12 +746,20 @@ int exprEndOffset = exprStartOffset + expressionText.length(); final CsmCompletionTokenProcessor tp = new CsmCompletionTokenProcessor(exprEndOffset, exprStartOffset); - TokenHierarchy hi = TokenHierarchy.create( - expressionText, - false, - CndLexerUtilities.getLanguage(getBaseDocument()), + + final Language language = getBaseDocument() != null ? + CndLexerUtilities.getLanguage(getBaseDocument()) + : CsmFileInfoQuery.getDefault().getFileLexerLanguage(getCsmFile()); + + final InputAttributes attributes = getBaseDocument() != null ? + (InputAttributes) getBaseDocument().getProperty(InputAttributes.class) + : null; + + TokenHierarchy hi = TokenHierarchy.create(expressionText, + false, + language, null, - (InputAttributes) getBaseDocument().getProperty(InputAttributes.class) + attributes ); List> tsList = hi.embeddedTokenSequences(exprEndOffset - exprStartOffset, true); // Go from inner to outer TSes @@ -777,6 +783,17 @@ return tp; } + + private CsmCompletionExpression getResultExpression(CsmCompletionTokenProcessor tp, boolean processedAsExpression, boolean keepWholeAst) { + if (processedAsExpression && keepWholeAst) { + // See implementation of processTokensInExpression + CsmCompletionExpression resultExp = tp.getResultExp(); + if (resultExp != null && resultExp.getParameterCount() == 1 && resultExp.getExpID() == CsmCompletionExpression.PARENTHESIS) { + return resultExp.getParameter(0); + } + } + return tp.getResultExp(); + } abstract protected boolean isProjectBeeingParsed(boolean openingSource); @@ -812,7 +829,7 @@ ); } } - CompletionSupport sup = CompletionSupport.get(doc); + CompletionSupport sup = CompletionSupport.get(doc, getCsmFile()); CsmOffsetableDeclaration context = sup.getDefinition(contextScope); if (context == null) { context = sup.getDefinition(getCsmFile(), offset, getFileReferencesContext()); @@ -1457,8 +1474,7 @@ if (CsmKindUtilities.isExpression(expression)) { tp = processTokensInExpression((CsmExpression) expression, true); } else { - long docVersion = DocumentUtilities.getDocumentVersion(getBaseDocument()); - tp = processTokensInFile(expression.getContainingFile(), expression.getStartOffset(), expression.getEndOffset(), getBaseDocument(), docVersion); + tp = processTokensInFile(expression.getContainingFile(), expression.getStartOffset(), expression.getEndOffset(), getBaseDocument()); } if (!checkErrorTokenState(tp)) { diff -r b647ecaa2068 cnd.lexer/src/org/netbeans/cnd/api/lexer/CndLexerUtilities.java --- a/cnd.lexer/src/org/netbeans/cnd/api/lexer/CndLexerUtilities.java Fri Sep 11 17:03:04 2015 +0300 +++ b/cnd.lexer/src/org/netbeans/cnd/api/lexer/CndLexerUtilities.java Wed Sep 16 20:03:55 2015 +0300 @@ -147,6 +147,39 @@ } return null; } + + /** + * returns C/C++/Preprocessor tokens sequence for text + * @param text cpp source text + * @param offset offset + * @param language language + * @param lexPP if true and offset is in preprocessor directive then return tokens sequence of this + * directive. If false and offset is in preprocessor directive do not dive into embedding + * @param backwardBias @see TokenHierarchy.embeddedTokenSequences + * If true the backward lying token will + * be used in case that the offset specifies position between + * two tokens. If false the forward lying token will be used. * + * @return token sequence positioned on token with offset (no need to call moveNext()/movePrevious() before token()) + */ + public static TokenSequence getCppTokenSequence(final Input text, final int offset, Language language, + boolean lexPP, boolean backwardBias) { + if (text == null) { + return null; + } + TokenHierarchy hi = TokenHierarchy.create(text, language); + List> tsList = hi.embeddedTokenSequences(offset, backwardBias); + // Go from inner to outer TSes + for (int i = tsList.size() - 1; i >= 0; i--) { + TokenSequence ts = tsList.get(i); + final Language lang = ts.languagePath().innerLanguage(); + if (isCppLanguage(lang, lexPP)) { + @SuppressWarnings("unchecked") + TokenSequence cppInnerTS = (TokenSequence) ts; + return cppInnerTS; + } + } + return null; + } public static TokenSequence getCppTokenSequenceWithoutEmbeddings(final Document doc, final int offset) { if (doc == null) { diff -r b647ecaa2068 cnd.model.services/src/org/netbeans/modules/cnd/api/model/services/CsmFileInfoQuery.java --- a/cnd.model.services/src/org/netbeans/modules/cnd/api/model/services/CsmFileInfoQuery.java Fri Sep 11 17:03:04 2015 +0300 +++ b/cnd.model.services/src/org/netbeans/modules/cnd/api/model/services/CsmFileInfoQuery.java Wed Sep 16 20:03:55 2015 +0300 @@ -47,6 +47,8 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import org.netbeans.api.lexer.TokenId; +import org.netbeans.api.lexer.TokenSequence; import org.netbeans.modules.cnd.api.model.CsmErrorDirective; import org.netbeans.modules.cnd.api.model.CsmFile; import org.netbeans.modules.cnd.api.model.CsmInclude; @@ -183,6 +185,27 @@ /** * + * @param file + * @return language for lexer + */ + public abstract org.netbeans.api.lexer.Language getFileLexerLanguage(CsmFile file); + + /** + * returns C/C++/Preprocessor tokens sequence for text + * @param file cpp source file + * @param offset offset + * @param lexPP if true and offset is in preprocessor directive then return tokens sequence of this + * directive. If false and offset is in preprocessor directive do not dive into embedding + * @param backwardBias @see TokenHierarchy.embeddedTokenSequences + * If true the backward lying token will + * be used in case that the offset specifies position between + * two tokens. If false the forward lying token will be used. * + * @return token sequence positioned on token with offset (no need to call moveNext()/movePrevious() before token()) + */ + public abstract TokenSequence getCppTokenSequence(final CsmFile file, final int offset, boolean lexPP, boolean backwardBias); + + /** + * * @param langFlavor - pair of language and flavor * @return pair of language and flavor in terms of APT */ @@ -320,6 +343,16 @@ } @Override + public org.netbeans.api.lexer.Language getFileLexerLanguage(CsmFile file) { + return null; + } + + @Override + public TokenSequence getCppTokenSequence(CsmFile file, int offset, boolean lexPP, boolean backwardBias) { + return null; + } + + @Override public Pair getAPTLanguageFlavor(Pair langFlavor) { return null; } diff -r b647ecaa2068 cnd.model.services/src/org/netbeans/modules/cnd/api/model/services/CsmMacroExpansion.java --- a/cnd.model.services/src/org/netbeans/modules/cnd/api/model/services/CsmMacroExpansion.java Fri Sep 11 17:03:04 2015 +0300 +++ b/cnd.model.services/src/org/netbeans/modules/cnd/api/model/services/CsmMacroExpansion.java Wed Sep 16 20:03:55 2015 +0300 @@ -206,6 +206,17 @@ public static int getOffsetInOriginalText(Document expandedDoc, int expandedOffset) { return getMacroExpansionDocProvider().getOffsetInOriginalText(expandedDoc, expandedOffset); } + + /** + * Transforms offset in expanded text to original offset. + * + * @param expandedFile - file + * @param expandedOffset - offset in expanded text + * @return original offset + */ + public static int getOffsetInOriginalText(CsmFile expandedFile, int expandedOffset) { + return getMacroExpansionDocProvider().getOffsetInOriginalText(expandedFile, expandedOffset); + } /** * Returns offset of the next macro expansion. @@ -291,11 +302,21 @@ } @Override + public int getOffsetInExpandedText(CsmFile expandedFile, int originalOffset) { + return originalOffset; + } + + @Override public int getOffsetInOriginalText(Document expandedDoc, int expandedOffset) { return expandedOffset; } @Override + public int getOffsetInOriginalText(CsmFile expandedFile, int expandedOffset) { + return expandedOffset; + } + + @Override public int getNextMacroExpansionStartOffset(Document expandedDoc, int expandedOffset) { return expandedOffset; } diff -r b647ecaa2068 cnd.model.services/src/org/netbeans/modules/cnd/spi/model/services/CsmMacroExpansionDocProvider.java --- a/cnd.model.services/src/org/netbeans/modules/cnd/spi/model/services/CsmMacroExpansionDocProvider.java Fri Sep 11 17:03:04 2015 +0300 +++ b/cnd.model.services/src/org/netbeans/modules/cnd/spi/model/services/CsmMacroExpansionDocProvider.java Wed Sep 16 20:03:55 2015 +0300 @@ -126,6 +126,15 @@ * @return offset in expanded text */ public int getOffsetInExpandedText(Document expandedDoc, int originalOffset); + + /** + * Transforms original offset to offset in expanded text. + * + * @param expandedFile - file + * @param originalOffset - original offset + * @return offset in expanded text + */ + public int getOffsetInExpandedText(CsmFile expandedFile, int originalOffset); /** * Transforms offset in expanded text to original offset. @@ -135,6 +144,15 @@ * @return original offset */ public int getOffsetInOriginalText(Document expandedDoc, int expandedOffset); + + /** + * Transforms offset in expanded text to original offset. + * + * @param expandedFile - file + * @param expandedOffset - offset in expanded text + * @return original offset + */ + public int getOffsetInOriginalText(CsmFile expandedFile, int expandedOffset); /** * Returns offset of the next macro expansion. diff -r b647ecaa2068 cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/csm/core/FileImpl.java --- a/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/csm/core/FileImpl.java Fri Sep 11 17:03:04 2015 +0300 +++ b/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/csm/core/FileImpl.java Wed Sep 16 20:03:55 2015 +0300 @@ -53,6 +53,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -220,6 +221,8 @@ private static volatile AtomicLong parseCount = new AtomicLong(1); private Collection parsingErrors; + + private final Map properties = Collections.synchronizedMap(new HashMap<>()); public static void incParseCount() { parseCount.incrementAndGet(); @@ -1804,6 +1807,16 @@ checkNotInParsingThreadImpl(); return currentFileContent.getScopeElements(); } + + @Override + public Object getProperty(Object key) { + return properties.get(key); + } + + @Override + public void putProperty(Object key, Object value) { + properties.put(key, value); + } public void setFileGuard(int guardStart, int guardEnd) { this.guardStart = guardStart; diff -r b647ecaa2068 cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/csm/core/FileSnapshot.java --- a/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/csm/core/FileSnapshot.java Fri Sep 11 17:03:04 2015 +0300 +++ b/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/csm/core/FileSnapshot.java Wed Sep 16 20:03:55 2015 +0300 @@ -87,6 +87,16 @@ } @Override + public Object getProperty(Object key) { + return delegate.getProperty(key); + } + + @Override + public void putProperty(Object key, Object value) { + delegate.putProperty(key, value); + } + + @Override public CharSequence getAbsolutePath() { return absPath; } diff -r b647ecaa2068 cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/csm/core/Unresolved.java --- a/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/csm/core/Unresolved.java Fri Sep 11 17:03:04 2015 +0300 +++ b/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/csm/core/Unresolved.java Wed Sep 16 20:03:55 2015 +0300 @@ -286,6 +286,16 @@ public void dispose() { UIDUtilities.disposeUnresolved(uid); } + + @Override + public Object getProperty(Object key) { + return null; + } + + @Override + public void putProperty(Object key, Object value) { + // do nothing + } }; // only one of projectRef/projectUID must be used (based on USE_UID_TO_CONTAINER) diff -r b647ecaa2068 cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/impl/services/FileInfoQueryImpl.java --- a/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/impl/services/FileInfoQueryImpl.java Fri Sep 11 17:03:04 2015 +0300 +++ b/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/impl/services/FileInfoQueryImpl.java Wed Sep 16 20:03:55 2015 +0300 @@ -37,14 +37,23 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.Objects; +import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import org.netbeans.api.lexer.Language; +import org.netbeans.api.lexer.TokenId; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.cnd.api.lexer.CndLexerUtilities; +import org.netbeans.cnd.api.lexer.CppTokenId; import org.netbeans.lib.editor.util.CharSequenceUtilities; import org.netbeans.modules.cnd.api.model.CsmErrorDirective; import org.netbeans.modules.cnd.api.model.CsmFile; import org.netbeans.modules.cnd.api.model.CsmInclude; import org.netbeans.modules.cnd.api.model.CsmOffsetable; import org.netbeans.modules.cnd.api.model.CsmUID; +import org.netbeans.modules.cnd.api.model.services.CsmCacheManager; +import org.netbeans.modules.cnd.api.model.services.CsmCacheMap; import org.netbeans.modules.cnd.api.model.services.CsmCompilationUnit; import org.netbeans.modules.cnd.api.model.services.CsmFileInfoQuery; import org.netbeans.modules.cnd.api.model.xref.CsmReference; @@ -85,6 +94,15 @@ @org.openide.util.lookup.ServiceProvider(service=org.netbeans.modules.cnd.api.model.services.CsmFileInfoQuery.class) public final class FileInfoQueryImpl extends CsmFileInfoQuery { + private static final Callable TOKEN_SEQUENCE_CACHE_INITIALIZER = new Callable() { + + @Override + public CsmCacheMap call() { + return new CsmCacheMap("FileInfoQueryImpl: get token sequence", 1); // NOI18N + } + + }; + @Override public boolean isCpp98OrLater(CsmFile csmFile) { if (csmFile != null) { @@ -416,6 +434,53 @@ } return Pair.of(NativeFileItem.Language.OTHER, NativeFileItem.LanguageFlavor.UNKNOWN); } + + @Override + public Language getFileLexerLanguage(CsmFile file) { + Pair fileLanguageFlavor = getFileLanguageFlavor(file); + switch (fileLanguageFlavor.first()) { + case C: + return CppTokenId.languageC(); + case CPP: + return CppTokenId.languageCpp(); + case C_HEADER: + return CppTokenId.languageHeader(); + default: + return null; + } + } + + /** + * returns C/C++/Preprocessor tokens sequence for text + * @param file cpp source file + * @param offset offset + * @param lexPP if true and offset is in preprocessor directive then return tokens sequence of this + * directive. If false and offset is in preprocessor directive do not dive into embedding + * @param backwardBias @see TokenHierarchy.embeddedTokenSequences + * If true the backward lying token will + * be used in case that the offset specifies position between + * two tokens. If false the forward lying token will be used. * + * @return token sequence positioned on token with offset (no need to call moveNext()/movePrevious() before token()) + */ + @Override + public TokenSequence getCppTokenSequence(final CsmFile file, final int offset, boolean lexPP, boolean backwardBias) { + Language lexerLanguage = getFileLexerLanguage(file); + CsmCacheMap cache = getTokenSequenceCache(); + TokenSequenceRequest key = new TokenSequenceRequest(lexerLanguage, getFileVersion(file), file); + boolean[] found = new boolean[] { false }; + Object cached = CsmCacheMap.getFromCache(cache, key, found); + if (cached != null && found[0]) { + return (TokenSequence) cached; + } else { + long time = System.currentTimeMillis(); + TokenSequence cppTokenSequence = CndLexerUtilities.getCppTokenSequence(file.getText(), offset, lexerLanguage, lexPP, backwardBias); + time = System.currentTimeMillis() - time; + if (cache != null) { + cache.put(key, CsmCacheMap.toValue(cppTokenSequence, time)); + } + return cppTokenSequence; + } + } private int getLangPriority(NativeFileItem.Language lang) { if (lang == null) { @@ -664,4 +729,56 @@ } return new int[]{0, 0}; } + + private CsmCacheMap getTokenSequenceCache() { + return CsmCacheManager.getClientCache(TokenSequenceRequest.class, TOKEN_SEQUENCE_CACHE_INITIALIZER); + } + + private static final class TokenSequenceRequest { + + private final Language language; + + private final long fileVersion; + + private final CsmFile file; + + public TokenSequenceRequest(Language language, long fileVersion, CsmFile file) { + this.language = language; + this.fileVersion = fileVersion; + this.file = file; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 71 * hash + Objects.hashCode(this.language); + hash = 71 * hash + (int) (this.fileVersion ^ (this.fileVersion >>> 32)); + hash = 71 * hash + Objects.hashCode(this.file); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final TokenSequenceRequest other = (TokenSequenceRequest) obj; + if (this.fileVersion != other.fileVersion) { + return false; + } + if (!Objects.equals(this.language, other.language)) { + return false; + } + if (!Objects.equals(this.file, other.file)) { + return false; + } + return true; + } + } } diff -r b647ecaa2068 cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/impl/services/MacroExpansionDocProviderImpl.java --- a/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/impl/services/MacroExpansionDocProviderImpl.java Fri Sep 11 17:03:04 2015 +0300 +++ b/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/impl/services/MacroExpansionDocProviderImpl.java Wed Sep 16 20:03:55 2015 +0300 @@ -229,6 +229,16 @@ } return originalOffset; } + + @Override + public int getOffsetInExpandedText(CsmFile expandedFile, int originalOffset) { + Object o = expandedFile.getProperty(MACRO_EXPANSION_OFFSET_TRANSFORMER); + if (o != null && o instanceof TransformationTable) { + TransformationTable tt = (TransformationTable) o; + return tt.getOutOffset(originalOffset); + } + return originalOffset; + } @Override public int getOffsetInOriginalText(Document expandedDoc, int expandedOffset) { @@ -239,6 +249,16 @@ } return expandedOffset; } + + @Override + public int getOffsetInOriginalText(CsmFile expandedFile, int expandedOffset) { + Object o = expandedFile.getProperty(MACRO_EXPANSION_OFFSET_TRANSFORMER); + if (o != null && o instanceof TransformationTable) { + TransformationTable tt = (TransformationTable) o; + return tt.getInOffset(expandedOffset); + } + return expandedOffset; + } @Override public int getNextMacroExpansionStartOffset(Document expandedDoc, int expandedOffset) {