mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Bug 425711: User preference to limit tokens per translation unit
This adds a new scalability preference that aborts parsing when too many Tokens are created for a single translation unit. This is a heuristic that fairly close predicts the files that will be too complex for the indexer to handle. The token counter is disabled by default. When it is enabled, the default token limit is 25,000,000. This value was determined by counting the number of Tokens produced for each translation unit in the boost-1.55.0 sources: sqlite> select * from counts where count > 10000000; count location ----------------------------------------------------------------- 100000001 libs/local_function/test/all_decl.cpp 100000001 libs/local_function/test/all_decl_seq.cpp 100000001 libs/local_function/test/all_decl_seq_nova.cpp 100000001 libs/preprocessor/doc/examples/array_arithmetic.c 99808587 libs/function_types/build/preprocess_arity_loops.cpp 62380381 libs/preprocessor/doc/examples/delay.c 58096841 libs/serialization/performance/xml/string256_test.cpp 58096828 libs/serialization/performance/xml/int256_test.cpp 52898416 libs/mpi/src/python/collectives.cpp 52573708 boost/spirit/home/support/char_encoding/ \ unicode/create_tables.cpp 21315014 libs/utility/binary_test.cpp 18799536 libs/math/test/test_rational_instances/ \ test_rational_double1.cpp 17758615 libs/mpl/test/string.cpp 13100401 libs/container/bench/bench_set.cpp 11976021 libs/local_function/example/const_block.cpp 11381198 libs/math/test/test_tr1.cpp 10432186 libs/parameter/test/preprocessor.cpp This value means that the indexer will process all files in boost without running out of memory on a 1Gb heap. Change-Id: Ia9fc73dfb38454cc8735f537e3ac6e661864fb4f Signed-off-by: Andrew Eidsness <eclipse@jfront.com> Reviewed-on: https://git.eclipse.org/r/22386 Reviewed-by: Doug Schaefer <dschaefer@qnx.com> IP-Clean: Doug Schaefer <dschaefer@qnx.com> Tested-by: Doug Schaefer <dschaefer@qnx.com>
This commit is contained in:
parent
4aa3f06bb4
commit
f7d49e5bde
16 changed files with 501 additions and 63 deletions
|
@ -22,19 +22,15 @@ import java.util.Map.Entry;
|
|||
import java.util.Vector;
|
||||
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.CCorePreferenceConstants;
|
||||
import org.eclipse.cdt.core.cdtvariables.CdtVariableException;
|
||||
import org.eclipse.cdt.core.cdtvariables.ICdtVariableManager;
|
||||
import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsChangeEvent;
|
||||
import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsChangeListener;
|
||||
import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager;
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
import org.eclipse.cdt.core.parser.ExtendedScannerInfo;
|
||||
import org.eclipse.cdt.core.parser.IParserSettings;
|
||||
import org.eclipse.cdt.core.parser.IScannerInfo;
|
||||
import org.eclipse.cdt.core.parser.IScannerInfoChangeListener;
|
||||
import org.eclipse.cdt.core.parser.IScannerInfoProvider;
|
||||
import org.eclipse.cdt.core.parser.ParserSettings;
|
||||
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
|
||||
import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
|
||||
import org.eclipse.cdt.core.settings.model.ICMacroEntry;
|
||||
|
@ -42,7 +38,7 @@ import org.eclipse.cdt.core.settings.model.ICPathEntry;
|
|||
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
|
||||
import org.eclipse.cdt.core.settings.model.ICSettingEntry;
|
||||
import org.eclipse.cdt.core.settings.model.util.CDataUtil;
|
||||
import org.eclipse.cdt.internal.core.model.CModelManager;
|
||||
import org.eclipse.cdt.internal.core.parser.ParserSettings2;
|
||||
import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager;
|
||||
import org.eclipse.cdt.internal.core.settings.model.SettingsModelMessages;
|
||||
import org.eclipse.cdt.utils.EFSExtensionManager;
|
||||
|
@ -134,25 +130,10 @@ public class LanguageSettingsScannerInfoProvider implements IScannerInfoProvider
|
|||
}
|
||||
|
||||
ExtendedScannerInfo extendedScannerInfo = new ExtendedScannerInfo(definedMacros, includePaths, macroFiles, includeFiles, includePathsLocal);
|
||||
|
||||
IParserSettings parserSettings = createParserSettings(project);
|
||||
extendedScannerInfo.setParserSettings(parserSettings);
|
||||
extendedScannerInfo.setParserSettings(new ParserSettings2(project));
|
||||
return extendedScannerInfo;
|
||||
}
|
||||
|
||||
private IParserSettings createParserSettings(IProject project) {
|
||||
ParserSettings parserSettings = new ParserSettings();
|
||||
ICProject cProject = CModelManager.getDefault().create(project);
|
||||
if (CCorePreferenceConstants.getPreference(CCorePreferenceConstants.SCALABILITY_SKIP_TRIVIAL_EXPRESSIONS, cProject,
|
||||
CCorePreferenceConstants.DEFAULT_SCALABILITY_SKIP_TRIVIAL_EXPRESSIONS)) {
|
||||
int maximumNumberOfTrivialExpressionsInAggregateInitializers = CCorePreferenceConstants.getPreference(
|
||||
CCorePreferenceConstants.SCALABILITY_MAXIMUM_TRIVIAL_EXPRESSIONS, cProject,
|
||||
CCorePreferenceConstants.DEFAULT_SCALABILITY_MAXIMUM_TRIVIAL_EXPRESSIONS);
|
||||
parserSettings.setMaximumTrivialExpressionsInAggregateInitializers(maximumNumberOfTrivialExpressionsInAggregateInitializers);
|
||||
}
|
||||
return parserSettings;
|
||||
}
|
||||
|
||||
private String expandVariables(String pathStr, ICConfigurationDescription cfgDescription) {
|
||||
try {
|
||||
ICdtVariableManager varManager = CCorePlugin.getDefault().getCdtVariableManager();
|
||||
|
|
|
@ -35,6 +35,8 @@ import org.eclipse.cdt.core.parser.IParserSettings;
|
|||
import org.eclipse.cdt.core.parser.IScanner;
|
||||
import org.eclipse.cdt.core.parser.IScannerInfo;
|
||||
import org.eclipse.cdt.core.parser.IncludeFileContentProvider;
|
||||
import org.eclipse.cdt.core.parser.ParseError;
|
||||
import org.eclipse.cdt.core.parser.ParseError.ParseErrorKind;
|
||||
import org.eclipse.cdt.core.parser.ParserLanguage;
|
||||
import org.eclipse.cdt.core.parser.ParserMode;
|
||||
import org.eclipse.cdt.internal.core.parser.scanner.CPreprocessor;
|
||||
|
@ -165,6 +167,20 @@ public abstract class AbstractCLikeLanguage extends AbstractLanguage implements
|
|||
IASTTranslationUnit ast= parser.parse();
|
||||
ast.setIsHeaderUnit((options & OPTION_IS_SOURCE_UNIT) == 0);
|
||||
return ast;
|
||||
} catch(ParseError e) {
|
||||
// Only the TOO_MANY_TOKENS error can be handled here.
|
||||
if (e.getErrorKind() != ParseErrorKind.TOO_MANY_TOKENS)
|
||||
throw e;
|
||||
|
||||
// Otherwise generate a log because parsing was stopped because of a user preference.
|
||||
if (log != null) {
|
||||
String tuName = null;
|
||||
if (scanner.getLocationResolver() != null)
|
||||
tuName = scanner.getLocationResolver().getTranslationUnitPath();
|
||||
|
||||
log.traceLog(e.getMessage() + (tuName == null ? new String() : (" while parsing " + tuName))); //$NON-NLS-1$
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
if (canceler != null) {
|
||||
canceler.setCancelable(null);
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2014 QNX Software Systems and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.cdt.core.parser;
|
||||
|
||||
/**
|
||||
* Interface for providing settings for the parser.
|
||||
* <p>
|
||||
* The first version of the interface was not marked with no-implement, so methods
|
||||
* cannot be added to it. This version should be used going forward. It is marked
|
||||
* no-implement and a Default implementation is provided. Clients should base their
|
||||
* own implementations on Default in order to avoid being broken by futured additions
|
||||
* to this interface.
|
||||
*
|
||||
* @since 5.7
|
||||
* @noimplement Extend {@link IParserSettings2.Default} instead.
|
||||
*/
|
||||
public interface IParserSettings2 extends IParserSettings {
|
||||
/**
|
||||
* An default implementation to be used as a base class by clients that want to
|
||||
* contribute parser settings. This base provides default values for all methods
|
||||
* so that clients will still compile when methods are added to the interface.
|
||||
*
|
||||
* @noinstantiate This class is not intended to be instantiated by clients.
|
||||
*/
|
||||
public static class Default extends ParserSettings implements IParserSettings2 {
|
||||
@Override
|
||||
public boolean shouldLimitTokensPerTranslationUnit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaximumTokensPerTranslationUnit() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the parser should be aborted when a single translation unit has produced
|
||||
* more than {@link #getMaximumTokensPerTranslationUnit()} tokens.
|
||||
*/
|
||||
public boolean shouldLimitTokensPerTranslationUnit();
|
||||
|
||||
/**
|
||||
* Returns the maximum number of tokens that should be created while parsing any one translation unit.
|
||||
* This value is used only when {@link #shouldLimitTokensPerTranslationUnit()} returns true.
|
||||
*/
|
||||
public int getMaximumTokensPerTranslationUnit();
|
||||
}
|
|
@ -35,6 +35,14 @@ public class ParseError extends Error {
|
|||
OFFSET_RANGE_NOT_NAME,
|
||||
|
||||
TIMEOUT_OR_CANCELLED,
|
||||
|
||||
/**
|
||||
* The user preference for {@link CCorePreferenceConstants#SCALABILITY_LIMIT_TOKENS_PER_TU} is enabled
|
||||
* and more than {@link CCorePreferenceConstants#SCALABILITY_MAXIMUM_TOKENS} tokens were created while
|
||||
* parsing a single translation unit.
|
||||
* @since 5.7
|
||||
*/
|
||||
TOO_MANY_TOKENS
|
||||
}
|
||||
|
||||
public ParseErrorKind getErrorKind()
|
||||
|
@ -46,4 +54,12 @@ public class ParseError extends Error {
|
|||
{
|
||||
errorKind = kind;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 5.7
|
||||
*/
|
||||
public ParseError(String message, ParseErrorKind kind) {
|
||||
super(message);
|
||||
errorKind = kind;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2014 QNX Software Systems and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.cdt.internal.core.parser;
|
||||
|
||||
import org.eclipse.cdt.core.CCorePreferenceConstants;
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
import org.eclipse.cdt.core.parser.IParserSettings2;
|
||||
import org.eclipse.cdt.internal.core.model.CModelManager;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
|
||||
public class ParserSettings2 extends IParserSettings2.Default {
|
||||
private final boolean limitTokensPerTU;
|
||||
private final int maxTokensPerTU;
|
||||
|
||||
public ParserSettings2() {
|
||||
this((ICProject) null);
|
||||
}
|
||||
|
||||
public ParserSettings2(IProject project) {
|
||||
this(CModelManager.getDefault().create(project));
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the specified project when looking for preferences for the settings object that is
|
||||
* being constructed.
|
||||
*
|
||||
* @param cProject The project from which the settings should be loaded, can be null.
|
||||
*/
|
||||
public ParserSettings2(ICProject cProject) {
|
||||
this.limitTokensPerTU
|
||||
= CCorePreferenceConstants.getPreference(
|
||||
CCorePreferenceConstants.SCALABILITY_LIMIT_TOKENS_PER_TU,
|
||||
cProject,
|
||||
CCorePreferenceConstants.DEFAULT_SCALABILITY_LIMIT_TOKENS_PER_TU);
|
||||
this.maxTokensPerTU
|
||||
= CCorePreferenceConstants.getPreference(
|
||||
CCorePreferenceConstants.SCALABILITY_MAXIMUM_TOKENS,
|
||||
cProject,
|
||||
CCorePreferenceConstants.DEFAULT_SCALABILITY_MAXIMUM_TOKENS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the parser should be aborted when a single translation unit has produced
|
||||
* more than {@link #getMaximumTokensPerTranslationUnit()} tokens.
|
||||
*/
|
||||
@Override
|
||||
public boolean shouldLimitTokensPerTranslationUnit() {
|
||||
return limitTokensPerTU;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of tokens that should be created while parsing any one translation unit.
|
||||
* This value will only be used when {@link #shouldLimitTokensPerTranslationUnit()} returns true.
|
||||
*/
|
||||
@Override
|
||||
public int getMaximumTokensPerTranslationUnit() {
|
||||
return maxTokensPerTU;
|
||||
}
|
||||
}
|
|
@ -272,6 +272,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
public CPreprocessor(FileContent fileContent, IScannerInfo info, ParserLanguage language,
|
||||
IParserLogService log, IScannerExtensionConfiguration configuration,
|
||||
IncludeFileContentProvider readerFactory) {
|
||||
Token.resetCounterFor(info);
|
||||
if (readerFactory instanceof InternalFileContentProvider) {
|
||||
fFileContentProvider= (InternalFileContentProvider) readerFactory;
|
||||
} else if (readerFactory == null) {
|
||||
|
|
|
@ -10,7 +10,12 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.parser.scanner;
|
||||
|
||||
import org.eclipse.cdt.core.parser.ExtendedScannerInfo;
|
||||
import org.eclipse.cdt.core.parser.IParserSettings;
|
||||
import org.eclipse.cdt.core.parser.IParserSettings2;
|
||||
import org.eclipse.cdt.core.parser.IScannerInfo;
|
||||
import org.eclipse.cdt.core.parser.IToken;
|
||||
import org.eclipse.cdt.core.parser.ParseError;
|
||||
|
||||
/**
|
||||
* Represents tokens found by the lexer. The preprocessor reuses the tokens and passes
|
||||
|
@ -24,7 +29,10 @@ public class Token implements IToken, Cloneable {
|
|||
private IToken fNextToken;
|
||||
Object fSource;
|
||||
|
||||
private static final Counter tokenCounter = new Counter();
|
||||
|
||||
Token(int kind, Object source, int offset, int endOffset) {
|
||||
tokenCounter.inc();
|
||||
fKind= kind;
|
||||
fOffset= offset;
|
||||
fEndOffset= endOffset;
|
||||
|
@ -99,9 +107,59 @@ public class Token implements IToken, Cloneable {
|
|||
@Override
|
||||
final public Token clone() {
|
||||
try {
|
||||
tokenCounter.inc();
|
||||
return (Token) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Either disable the token counter or reset it to the limit in the given scanner info object.
|
||||
*/
|
||||
public static void resetCounterFor(IScannerInfo info) {
|
||||
tokenCounter.reset(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bug 425711: Some source files cause the CPreprocessor to try to allocate an unmanageable number
|
||||
* of Tokens. For example, boost has a file, delay.c, that caused over 250 million instances to
|
||||
* be created -- that is where the VM overflowed my 3Gb heap. Both gcc and clang also ran
|
||||
* out of memory and crashed while processing that file.
|
||||
* <p>
|
||||
* Giving up on a file is better than crashing the entire IDE, so a new user-preference provide
|
||||
* a way to specify a limit. The preference is implemented by counting the number of instances
|
||||
* of Token that are created by a single instance of CPreprocessor.
|
||||
* <p>
|
||||
* This counter records the total and throws an exception if the limit is surpassed.
|
||||
*/
|
||||
private static class Counter {
|
||||
public int count = 0;
|
||||
public int limit = -1;
|
||||
|
||||
public void reset(IScannerInfo info) {
|
||||
// The counters are always reset, we optionally apply a new limit if the settings
|
||||
// are found.
|
||||
count = 0;
|
||||
limit = -1;
|
||||
|
||||
if (info instanceof ExtendedScannerInfo) {
|
||||
IParserSettings settings = ((ExtendedScannerInfo) info).getParserSettings();
|
||||
if (settings instanceof IParserSettings2) {
|
||||
IParserSettings2 parserSettings = (IParserSettings2) settings;
|
||||
if (parserSettings.shouldLimitTokensPerTranslationUnit()) {
|
||||
int maxTokens = parserSettings.getMaximumTokensPerTranslationUnit();
|
||||
if (maxTokens > 0)
|
||||
limit = maxTokens;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void inc() throws ParseError {
|
||||
if (limit > 0
|
||||
&& ++count > limit)
|
||||
throw new ParseError(Integer.toString(count) + " tokens", ParseError.ParseErrorKind.TOO_MANY_TOKENS);//$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,6 @@ import org.eclipse.cdt.core.parser.IScannerInfo;
|
|||
import org.eclipse.cdt.core.parser.ISignificantMacros;
|
||||
import org.eclipse.cdt.core.parser.IncludeExportPatterns;
|
||||
import org.eclipse.cdt.core.parser.IncludeFileContentProvider;
|
||||
import org.eclipse.cdt.core.parser.ParserSettings;
|
||||
import org.eclipse.cdt.core.parser.ParserUtil;
|
||||
import org.eclipse.cdt.internal.core.dom.IIncludeFileResolutionHeuristics;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit;
|
||||
|
@ -64,6 +63,7 @@ import org.eclipse.cdt.internal.core.index.IIndexFragmentFile;
|
|||
import org.eclipse.cdt.internal.core.index.IWritableIndex;
|
||||
import org.eclipse.cdt.internal.core.index.IndexBasedFileContentProvider;
|
||||
import org.eclipse.cdt.internal.core.parser.IMacroDictionary;
|
||||
import org.eclipse.cdt.internal.core.parser.ParserSettings2;
|
||||
import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContentProvider;
|
||||
import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContentProvider.DependsOnOutdatedFileException;
|
||||
import org.eclipse.cdt.internal.core.parser.util.LRUCache;
|
||||
|
@ -417,7 +417,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter {
|
|||
}
|
||||
|
||||
protected IParserSettings createParserSettings() {
|
||||
return new ParserSettings();
|
||||
return new ParserSettings2();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1043,7 +1043,9 @@ public abstract class AbstractIndexerTask extends PDOMWriter {
|
|||
long start= System.currentTimeMillis();
|
||||
IASTTranslationUnit ast= createAST(lang, codeReader, scanInfo, isSource, fASTOptions, ctx, pm);
|
||||
fStatistics.fParsingTime += System.currentTimeMillis() - start;
|
||||
if (ast != null) {
|
||||
if (ast == null) {
|
||||
++fStatistics.fTooManyTokensCount;
|
||||
} else {
|
||||
// Give the new AST a chance to recognize its translation unit before it is written
|
||||
// to the index.
|
||||
((ASTTranslationUnit) ast).setOriginatingTranslationUnit((ITranslationUnit) tu);
|
||||
|
|
|
@ -22,4 +22,5 @@ public class IndexerStatistics {
|
|||
public int fUnresolvedIncludesCount= 0;
|
||||
public int fPreprocessorProblemCount= 0;
|
||||
public int fSyntaxProblemsCount= 0;
|
||||
public int fTooManyTokensCount= 0;
|
||||
}
|
||||
|
|
|
@ -282,6 +282,9 @@ public abstract class PDOMIndexerTask extends AbstractIndexerTask implements IPD
|
|||
+ fStatistics.fUnresolvedIncludesCount + " include, " //$NON-NLS-1$
|
||||
+ fStatistics.fPreprocessorProblemCount + " scanner, " //$NON-NLS-1$
|
||||
+ fStatistics.fSyntaxProblemsCount + " syntax errors."); //$NON-NLS-1$
|
||||
if (fStatistics.fTooManyTokensCount > 0)
|
||||
System.out.println(ident + " Tokens: " //$NON-NLS-1$
|
||||
+ fStatistics.fTooManyTokensCount + " TUs with too many tokens."); //$NON-NLS-1$
|
||||
|
||||
NumberFormat nfPercent= NumberFormat.getPercentInstance();
|
||||
nfPercent.setMaximumFractionDigits(2);
|
||||
|
|
|
@ -250,6 +250,39 @@ public class CCorePreferenceConstants {
|
|||
*/
|
||||
public static final int DEFAULT_SCALABILITY_MAXIMUM_TRIVIAL_EXPRESSIONS = 1000;
|
||||
|
||||
/**
|
||||
* A named preference that specifies whether the parser should abort when too many Tokens are created
|
||||
* during parse of a single TU. This is a heuristic that is used to detect translation units that
|
||||
* are too complex to be handled the by the CDT parser.
|
||||
*
|
||||
* @since 5.7
|
||||
*/
|
||||
public static final String SCALABILITY_LIMIT_TOKENS_PER_TU = "scalability.limitTokensPerTU"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* Default value for {@link #SCALABILITY_LIMIT_TOKENS_PER_TU}.
|
||||
* @since 5.7
|
||||
*/
|
||||
public static final boolean DEFAULT_SCALABILITY_LIMIT_TOKENS_PER_TU = false;
|
||||
|
||||
/**
|
||||
* A named preference that specifies the parser's token limit. Parsing will be aborted when a single
|
||||
* translation unit has produced a maximum number of tokens. This is a heuristic that is used to
|
||||
* detect translation units that are too complex to be handled the by the CDT parser.
|
||||
*
|
||||
* @since 5.7
|
||||
*/
|
||||
public static final String SCALABILITY_MAXIMUM_TOKENS = "scalability.maximumTokens"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* Default value for {@link #SCALABILITY_MAXIMUM_TOKENS}.
|
||||
*
|
||||
* @since 5.7
|
||||
*/
|
||||
public static final int DEFAULT_SCALABILITY_MAXIMUM_TOKENS = 25 * 1000 * 1000;
|
||||
// NOTE: This default came from measurements using a 1Gb heap on a 64-bit VM. The test project was
|
||||
// boost-1.55.0. This default will index all but 9 files without running out of memory.
|
||||
|
||||
/**
|
||||
* Returns the node in the preference in the given context.
|
||||
* @param key The preference key.
|
||||
|
|
|
@ -71,5 +71,7 @@ public class CCorePreferenceInitializer extends AbstractPreferenceInitializer {
|
|||
// Scalability defaults.
|
||||
defaultPreferences.putBoolean(CCorePreferenceConstants.SCALABILITY_SKIP_TRIVIAL_EXPRESSIONS, CCorePreferenceConstants.DEFAULT_SCALABILITY_SKIP_TRIVIAL_EXPRESSIONS);
|
||||
defaultPreferences.putInt(CCorePreferenceConstants.SCALABILITY_MAXIMUM_TRIVIAL_EXPRESSIONS, CCorePreferenceConstants.DEFAULT_SCALABILITY_MAXIMUM_TRIVIAL_EXPRESSIONS);
|
||||
defaultPreferences.putBoolean(CCorePreferenceConstants.SCALABILITY_LIMIT_TOKENS_PER_TU, CCorePreferenceConstants.DEFAULT_SCALABILITY_LIMIT_TOKENS_PER_TU);
|
||||
defaultPreferences.putInt(CCorePreferenceConstants.SCALABILITY_MAXIMUM_TOKENS, CCorePreferenceConstants.DEFAULT_SCALABILITY_MAXIMUM_TOKENS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -555,6 +555,7 @@ public final class PreferencesMessages extends NLS {
|
|||
public static String ScalabilityPreferencePage_parserSettings_group_label;
|
||||
public static String ScalabilityPreferencePage_skipTrivialExpressions_label;
|
||||
public static String ScalabilityPreferencePage_maximumTrivialExpressions_label;
|
||||
public static String ScalabilityPreferencePage_maximumTokensPerTU_label;
|
||||
|
||||
public static String IndexerStrategyBlock_activeBuildConfig;
|
||||
public static String IndexerStrategyBlock_autoUpdate;
|
||||
|
|
|
@ -621,6 +621,7 @@ ScalabilityPreferencePage_preferenceOnlyForNewEditors=Some options do not affect
|
|||
ScalabilityPreferencePage_parserSettings_group_label= Parser settings
|
||||
ScalabilityPreferencePage_skipTrivialExpressions_label= Skip trivial expressions in initializer lists
|
||||
ScalabilityPreferencePage_maximumTrivialExpressions_label= Maximum number of trivial expressions in initializer lists to parse:
|
||||
ScalabilityPreferencePage_maximumTokensPerTU_label= Maximum number of tokens per translation unit:
|
||||
|
||||
IndexerStrategyBlock_strategyGroup=Indexing strategy
|
||||
IndexerStrategyBlock_autoUpdate=Automatically update the index
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* Copyright (c) 2014 QNX Software Systems and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.cdt.internal.ui.preferences;
|
||||
|
||||
import org.eclipse.jface.fieldassist.ControlDecoration;
|
||||
import org.eclipse.jface.fieldassist.FieldDecoration;
|
||||
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
|
||||
import org.eclipse.jface.preference.IntegerFieldEditor;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.FocusAdapter;
|
||||
import org.eclipse.swt.events.FocusEvent;
|
||||
import org.eclipse.swt.events.SelectionAdapter;
|
||||
import org.eclipse.swt.events.SelectionEvent;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
|
||||
/**
|
||||
* A field editor that combines an integer value preference with a boolean enablement
|
||||
* preference.
|
||||
*
|
||||
* @since 5.8
|
||||
*/
|
||||
public class ScalabilityIntegerFieldEditor extends IntegerFieldEditor {
|
||||
private ControlDecoration fDecoration;
|
||||
private final String fEnableKey;
|
||||
private Button fCheckbox;
|
||||
private boolean fWasSelected;
|
||||
|
||||
public ScalabilityIntegerFieldEditor(String enableKey, String nameKey, String labelText, Composite parent) {
|
||||
super(nameKey, labelText, parent);
|
||||
fEnableKey= enableKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Text getTextControl(Composite parent) {
|
||||
Text control = super.getTextControl(parent);
|
||||
if (fDecoration == null) {
|
||||
fDecoration = new ControlDecoration(control, SWT.LEFT | SWT.TOP);
|
||||
FieldDecoration errorDecoration = FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_ERROR);
|
||||
fDecoration.setImage(errorDecoration.getImage());
|
||||
fDecoration.setDescriptionText(getErrorMessage());
|
||||
|
||||
// validate on focus gain
|
||||
control.addFocusListener(new FocusAdapter() {
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) {
|
||||
refreshValidState();
|
||||
}
|
||||
});
|
||||
}
|
||||
return control;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void showErrorMessage(String msg) {
|
||||
super.showErrorMessage(msg);
|
||||
if (fDecoration != null) {
|
||||
fDecoration.setDescriptionText(msg);
|
||||
fDecoration.show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clearErrorMessage() {
|
||||
super.clearErrorMessage();
|
||||
if (fDecoration != null) {
|
||||
fDecoration.hide();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFillIntoGrid(Composite parent, int numColumns) {
|
||||
getCheckboxControl(parent);
|
||||
super.doFillIntoGrid(parent, numColumns);
|
||||
}
|
||||
|
||||
private Button getCheckboxControl(Composite parent) {
|
||||
if (fCheckbox == null) {
|
||||
Composite inner= new Composite(parent, SWT.NULL);
|
||||
final GridLayout layout= new GridLayout(2, false);
|
||||
layout.marginWidth = 0;
|
||||
inner.setLayout(layout);
|
||||
fCheckbox= new Button(inner, SWT.CHECK);
|
||||
fCheckbox.setFont(parent.getFont());
|
||||
fCheckbox.setText(getLabelText());
|
||||
// create and hide label from base class
|
||||
Label label = getLabelControl(inner);
|
||||
label.setText(""); //$NON-NLS-1$
|
||||
label.setVisible(false);
|
||||
fCheckbox.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
boolean isSelected = fCheckbox.getSelection();
|
||||
valueChanged(fWasSelected, isSelected);
|
||||
fWasSelected = isSelected;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
checkParent(fCheckbox.getParent(), parent);
|
||||
}
|
||||
return fCheckbox;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Label getLabelControl(Composite parent) {
|
||||
final Label label= getLabelControl();
|
||||
if (label == null) {
|
||||
return super.getLabelControl(parent);
|
||||
} else {
|
||||
checkParent(label.getParent(), parent);
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
protected void valueChanged(boolean oldValue, boolean newValue) {
|
||||
if (oldValue != newValue) {
|
||||
valueChanged();
|
||||
fireStateChanged(VALUE, oldValue, newValue);
|
||||
getTextControl().setEnabled(newValue);
|
||||
getLabelControl().setEnabled(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkState() {
|
||||
if (fCheckbox != null && !fCheckbox.getSelection()) {
|
||||
clearErrorMessage();
|
||||
return true;
|
||||
}
|
||||
return super.checkState();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLoad() {
|
||||
super.doLoad();
|
||||
if (fCheckbox != null) {
|
||||
boolean value = getPreferenceStore().getBoolean(fEnableKey);
|
||||
fCheckbox.setSelection(value);
|
||||
fWasSelected = value;
|
||||
getTextControl().setEnabled(value);
|
||||
getLabelControl().setEnabled(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLoadDefault() {
|
||||
super.doLoadDefault();
|
||||
if (fCheckbox != null) {
|
||||
boolean value = getPreferenceStore().getDefaultBoolean(fEnableKey);
|
||||
fCheckbox.setSelection(value);
|
||||
fWasSelected = value;
|
||||
getTextControl().setEnabled(value);
|
||||
getLabelControl().setEnabled(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStore() {
|
||||
super.doStore();
|
||||
getPreferenceStore().setValue(fEnableKey, fCheckbox.getSelection());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this field editor's current boolean value.
|
||||
*
|
||||
* @return the value
|
||||
*/
|
||||
public boolean getBooleanValue() {
|
||||
return fCheckbox.getSelection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the checkbox selection and enablement of the other controls as specified.
|
||||
*/
|
||||
public void setBooleanValue(boolean value) {
|
||||
// The checkbox selection will normally be propagated to the label and text controls in the
|
||||
// checkbox selection listener. However, the callback is only invoked when the selection changes,
|
||||
// which means that an initial value of false will not be properly propagated. The state is
|
||||
// directly updated here.
|
||||
if (fCheckbox != null) {
|
||||
fWasSelected = value;
|
||||
getLabelControl().setEnabled(value);
|
||||
getTextControl().setEnabled(value);
|
||||
fCheckbox.setSelection(value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,7 +19,6 @@ import java.util.Map;
|
|||
|
||||
import org.eclipse.jface.dialogs.Dialog;
|
||||
import org.eclipse.jface.dialogs.IDialogConstants;
|
||||
import org.eclipse.jface.preference.BooleanFieldEditor;
|
||||
import org.eclipse.jface.preference.FieldEditor;
|
||||
import org.eclipse.jface.preference.IPreferenceStore;
|
||||
import org.eclipse.jface.preference.IntegerFieldEditor;
|
||||
|
@ -63,14 +62,12 @@ public class ScalabilityPreferencePage extends PreferencePage implements IWorkbe
|
|||
private Button fSemanticHighlighting;
|
||||
|
||||
private Button fContentAssist;
|
||||
|
||||
|
||||
private Button fContentAssistAutoActivation;
|
||||
|
||||
private BooleanFieldEditor fSkipTrivialExpressions;
|
||||
private ScalabilityIntegerFieldEditor fMaximumTrivialExpressions;
|
||||
|
||||
private IntegerFieldEditor fMaximumTrivialExpressions;
|
||||
|
||||
private Composite fParserSettingsComposite;
|
||||
private ScalabilityIntegerFieldEditor fMaximumTokens;
|
||||
|
||||
private final Map<Object, String> fCheckBoxes= new HashMap<Object, String>();
|
||||
|
||||
|
@ -116,10 +113,8 @@ public class ScalabilityPreferencePage extends PreferencePage implements IWorkbe
|
|||
listener.widgetSelected(null);
|
||||
}
|
||||
fLinesToTrigger.setStringValue(Integer.toString(prefs.getInt(PreferenceConstants.SCALABILITY_NUMBER_OF_LINES)));
|
||||
fSkipTrivialExpressions.load();
|
||||
fMaximumTrivialExpressions.load();
|
||||
|
||||
updateEnable();
|
||||
fMaximumTokens.load();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -162,23 +157,23 @@ public class ScalabilityPreferencePage extends PreferencePage implements IWorkbe
|
|||
createParserSettings(composite);
|
||||
|
||||
new Separator().doFillIntoGrid(composite, nColumns);
|
||||
|
||||
|
||||
String noteTitle= PreferencesMessages.ScalabilityPreferencePage_note;
|
||||
String noteMessage= PreferencesMessages.ScalabilityPreferencePage_preferenceOnlyForNewEditors;
|
||||
Composite noteControl= createNoteComposite(JFaceResources.getDialogFont(), composite, noteTitle, noteMessage);
|
||||
GridData gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
|
||||
gd.horizontalSpan= 2;
|
||||
noteControl.setLayoutData(gd);
|
||||
|
||||
|
||||
initFields();
|
||||
|
||||
|
||||
Dialog.applyDialogFont(composite);
|
||||
return composite;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates composite group and sets the default layout data.
|
||||
*
|
||||
*
|
||||
* @param parent
|
||||
* the parent of the new composite
|
||||
* @param numColumns
|
||||
|
@ -190,7 +185,7 @@ public class ScalabilityPreferencePage extends PreferencePage implements IWorkbe
|
|||
private Composite createGroupComposite( Composite parent, int numColumns, String labelText ) {
|
||||
return ControlFactory.createGroup( parent, labelText, numColumns );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the view setting preferences composite widget
|
||||
*/
|
||||
|
@ -228,30 +223,25 @@ public class ScalabilityPreferencePage extends PreferencePage implements IWorkbe
|
|||
}
|
||||
|
||||
private void createParserSettings(Composite parent) {
|
||||
final Composite parserSettingsGroup = createGroupComposite(parent, 1,
|
||||
PreferencesMessages.ScalabilityPreferencePage_parserSettings_group_label);
|
||||
Composite group = createGroupComposite( parent, 1, PreferencesMessages.ScalabilityPreferencePage_parserSettings_group_label );
|
||||
|
||||
final Composite skipTrivialComposite = new Composite(parserSettingsGroup, SWT.NONE);
|
||||
fSkipTrivialExpressions = new BooleanFieldEditor(CCorePreferenceConstants.SCALABILITY_SKIP_TRIVIAL_EXPRESSIONS,
|
||||
PreferencesMessages.ScalabilityPreferencePage_skipTrivialExpressions_label, skipTrivialComposite);
|
||||
fSkipTrivialExpressions.setPreferenceStore(CUIPlugin.getDefault().getCorePreferenceStore());
|
||||
|
||||
fParserSettingsComposite = new Composite(parserSettingsGroup, SWT.NONE);
|
||||
fMaximumTrivialExpressions = createIntegerField(fParserSettingsComposite,
|
||||
CCorePreferenceConstants.SCALABILITY_MAXIMUM_TRIVIAL_EXPRESSIONS,
|
||||
PreferencesMessages.ScalabilityPreferencePage_maximumTrivialExpressions_label, 0, Integer.MAX_VALUE);
|
||||
fMaximumTrivialExpressions
|
||||
= createScalabilityIntegerField(
|
||||
group,
|
||||
CCorePreferenceConstants.SCALABILITY_SKIP_TRIVIAL_EXPRESSIONS,
|
||||
CCorePreferenceConstants.SCALABILITY_MAXIMUM_TRIVIAL_EXPRESSIONS,
|
||||
PreferencesMessages.ScalabilityPreferencePage_skipTrivialExpressions_label,
|
||||
1, Integer.MAX_VALUE);
|
||||
fMaximumTrivialExpressions.setPreferenceStore(CUIPlugin.getDefault().getCorePreferenceStore());
|
||||
|
||||
fSkipTrivialExpressions.setPropertyChangeListener(new IPropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent event) {
|
||||
updateEnable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateEnable() {
|
||||
fMaximumTrivialExpressions.setEnabled(fSkipTrivialExpressions.getBooleanValue(), fParserSettingsComposite);
|
||||
fMaximumTokens
|
||||
= createScalabilityIntegerField(
|
||||
group,
|
||||
CCorePreferenceConstants.SCALABILITY_LIMIT_TOKENS_PER_TU,
|
||||
CCorePreferenceConstants.SCALABILITY_MAXIMUM_TOKENS,
|
||||
PreferencesMessages.ScalabilityPreferencePage_maximumTokensPerTU_label,
|
||||
1, 1000000000);
|
||||
fMaximumTokens.setPreferenceStore(CUIPlugin.getDefault().getCorePreferenceStore());
|
||||
}
|
||||
|
||||
private IntegerFieldEditor createIntegerField(Composite parent, String name, String labelText, int rangeMinimum, int rangeMaximum) {
|
||||
|
@ -276,6 +266,28 @@ public class ScalabilityPreferencePage extends PreferencePage implements IWorkbe
|
|||
return integerField;
|
||||
}
|
||||
|
||||
private ScalabilityIntegerFieldEditor createScalabilityIntegerField(Composite parent, String enable, String name, String labelText, int rangeMinimum, int rangeMaximum) {
|
||||
final ScalabilityIntegerFieldEditor field = new ScalabilityIntegerFieldEditor(enable, name, labelText, parent);
|
||||
|
||||
GridData data = (GridData) field.getTextControl(parent).getLayoutData();
|
||||
data.horizontalAlignment = GridData.BEGINNING;
|
||||
data.widthHint = convertWidthInCharsToPixels(11);
|
||||
field.setPage(this);
|
||||
field.setValidateStrategy(StringFieldEditor.VALIDATE_ON_KEY_STROKE);
|
||||
field.setValidRange(rangeMinimum, rangeMaximum);
|
||||
field.setErrorMessage(NLS.bind(PreferencesMessages.ScalabilityPreferencePage_error,
|
||||
new Object[] { rangeMinimum, rangeMaximum }));
|
||||
field.load();
|
||||
field.setPropertyChangeListener(new IPropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent event) {
|
||||
if (event.getProperty().equals(FieldEditor.IS_VALID))
|
||||
setValid(field.isValid());
|
||||
}
|
||||
});
|
||||
return field;
|
||||
}
|
||||
|
||||
private static void indent(Control control, GridData masterLayoutData) {
|
||||
GridData gridData= new GridData();
|
||||
gridData.horizontalIndent= masterLayoutData.horizontalIndent + 20;
|
||||
|
@ -329,8 +341,8 @@ public class ScalabilityPreferencePage extends PreferencePage implements IWorkbe
|
|||
prefs.setValue(key, b.getSelection());
|
||||
}
|
||||
prefs.setValue(PreferenceConstants.SCALABILITY_NUMBER_OF_LINES, fLinesToTrigger.getIntValue());
|
||||
fSkipTrivialExpressions.store();
|
||||
fMaximumTrivialExpressions.store();
|
||||
fMaximumTokens.store();
|
||||
return super.performOk();
|
||||
}
|
||||
|
||||
|
@ -355,8 +367,7 @@ public class ScalabilityPreferencePage extends PreferencePage implements IWorkbe
|
|||
listener.widgetSelected(null);
|
||||
}
|
||||
fLinesToTrigger.setStringValue(Integer.toString(prefs.getDefaultInt(PreferenceConstants.SCALABILITY_NUMBER_OF_LINES)));
|
||||
fSkipTrivialExpressions.loadDefault();
|
||||
fMaximumTrivialExpressions.loadDefault();
|
||||
updateEnable();
|
||||
fMaximumTokens.loadDefault();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue