diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMLocationInclusionTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMLocationInclusionTests.java index ddc284ea9ba..82846d56284 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMLocationInclusionTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMLocationInclusionTests.java @@ -1,13 +1,13 @@ /******************************************************************************* - * Copyright (c) 2004, 2008 IBM Corporation and others. + * Copyright (c) 2004, 2011 IBM Corporation 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 * * Contributors: - * IBM - Initial API and implementation - * Markus Schorn (Wind River Systems) + * IBM - Initial API and implementation + * Markus Schorn (Wind River Systems) *******************************************************************************/ package org.eclipse.cdt.core.parser.tests.ast2; @@ -35,6 +35,7 @@ import org.eclipse.cdt.core.parser.ExtendedScannerInfo; import org.eclipse.cdt.core.parser.IExtendedScannerInfo; import org.eclipse.cdt.core.parser.IScannerInfo; import org.eclipse.cdt.core.parser.ParserLanguage; +import org.eclipse.cdt.core.parser.ScannerInfo; import org.eclipse.cdt.internal.core.dom.SavedCodeReaderFactory; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; @@ -70,9 +71,9 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { String code = "int main() { return BEAST * sizeof( Include ); } "; //$NON-NLS-1$ for (ParserLanguage p : ParserLanguage.values()) { String filename = (p == ParserLanguage.CPP) ? "main.cc" : "main.c"; //$NON-NLS-1$ //$NON-NLS-2$ - IFile c = importFile(filename, code); //$NON-NLS-1$ //$NON-NLS-2$ + IFile c = importFile(filename, code); - IASTTranslationUnit tu = parse(c, scannerInfo); //$NON-NLS-1$ + IASTTranslationUnit tu = parse(c, scannerInfo); IASTFunctionDefinition fd = (IASTFunctionDefinition) tu.getDeclarations()[3]; IASTFileLocation floc = fd.getFileLocation(); assertEquals(floc.getNodeOffset(), @@ -102,11 +103,11 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { for (ParserLanguage p : ParserLanguage.values()) { String filename = (p == ParserLanguage.CPP) ? "blah.cc" : "blah.c"; //$NON-NLS-1$ //$NON-NLS-2$ - IFile source = importFile(filename, code); //$NON-NLS-1$ - IASTTranslationUnit tu = parse(source); //$NON-NLS-1$ + IFile source = importFile(filename, code); + IASTTranslationUnit tu = parse(source); IASTSimpleDeclaration declaration = (IASTSimpleDeclaration) tu.getDeclarations()[0]; assertSoleFileLocation(declaration.getDeclarators()[0], filename, - code.indexOf("SomeStructure"), "SomeStructure".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + code.indexOf("SomeStructure"), "SomeStructure".length()); //$NON-NLS-1$ //$NON-NLS-2$ } } } @@ -206,13 +207,13 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { for (ParserLanguage p : ParserLanguage.values()) { String filename = (p == ParserLanguage.CPP) ? "code.cc" : "code.c"; //$NON-NLS-1$ //$NON-NLS-2$ - IFile cpp = importFile(filename, code); //$NON-NLS-1$ - IASTTranslationUnit tu = parse(cpp); //$NON-NLS-1$ + IFile cpp = importFile(filename, code); + IASTTranslationUnit tu = parse(cpp); IASTDeclaration[] declarations = tu.getDeclarations(); assertEquals(declarations.length, 2); IASTSimpleDeclaration bar = (IASTSimpleDeclaration) declarations[0]; IASTSimpleDeclaration FOO = (IASTSimpleDeclaration) declarations[1]; - assertSoleFileLocation(bar, filename, code.indexOf("int"), code.indexOf(";") + 1); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + assertSoleFileLocation(bar, filename, code.indexOf("int"), code.indexOf(";") + 1); //$NON-NLS-1$ //$NON-NLS-2$ assertSoleFileLocation(FOO, "foo.h", foo.indexOf("int"), foo.indexOf(";") + 1); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ IASTPreprocessorIncludeStatement[] incs = tu.getIncludeDirectives(); @@ -243,8 +244,8 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { for (ParserLanguage p : ParserLanguage.values()) { String filename = (p == ParserLanguage.CPP) ? "code.cc" : "code.c"; //$NON-NLS-1$ //$NON-NLS-2$ - IFile cpp = importFile(filename, code); //$NON-NLS-1$ - IASTTranslationUnit tu = parse(cpp); //$NON-NLS-1$ + IFile cpp = importFile(filename, code); + IASTTranslationUnit tu = parse(cpp); IASTDeclaration[] declarations = tu.getDeclarations(); assertEquals(declarations.length, 3); IASTSimpleDeclaration bar = (IASTSimpleDeclaration) declarations[0]; @@ -253,21 +254,21 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { assertSoleFileLocation( bar, filename, - code.indexOf("int"), code.indexOf("r;") + 2 - code.indexOf("int")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + code.indexOf("int"), code.indexOf("r;") + 2 - code.indexOf("int")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ assertSoleFileLocation( FOO, "foo.h", foo.indexOf("int"), foo.indexOf(";") + 1 - foo.indexOf("int")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ assertSoleFileLocation( byob, filename, - code.indexOf("float"), code.indexOf("b;") + 2 - code.indexOf("float")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + code.indexOf("float"), code.indexOf("b;") + 2 - code.indexOf("float")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ IASTPreprocessorIncludeStatement[] incs = tu.getIncludeDirectives(); assertNotNull(incs); assertEquals(incs.length, 1); assertSoleFileLocation( incs[0], filename, - code.indexOf("#inc"), code.indexOf(".h\"\n") + ".h\"".length() - code.indexOf("#inc")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + code.indexOf("#inc"), code.indexOf(".h\"\n") + ".h\"".length() - code.indexOf("#inc")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ } } @@ -278,8 +279,8 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { for (ParserLanguage p : ParserLanguage.values()) { String filename = (p == ParserLanguage.CPP) ? "blah.cc" : "blah.c"; //$NON-NLS-1$ //$NON-NLS-2$ - IFile c_file = importFile(filename, c_file_code); //$NON-NLS-1$ - IASTTranslationUnit tu = parse(c_file); //$NON-NLS-1$ + IFile c_file = importFile(filename, c_file_code); + IASTTranslationUnit tu = parse(c_file); assertEquals(tu.getDeclarations().length, 0); IASTPreprocessorMacroDefinition[] macroDefinitions = tu .getMacroDefinitions(); @@ -288,9 +289,9 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { assertSoleFileLocation( macroDefinitions[0], filename, - c_file_code.indexOf("#define"), c_file_code.indexOf("4") + 1 - c_file_code.indexOf("#define")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + c_file_code.indexOf("#define"), c_file_code.indexOf("4") + 1 - c_file_code.indexOf("#define")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ assertSoleFileLocation(macroDefinitions[0].getName(), filename, - c_file_code.indexOf("X"), 1); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + c_file_code.indexOf("X"), 1); //$NON-NLS-1$ assertSoleFileLocation( macroDefinitions[1], "blarg.h", h_file_code.indexOf("#define _BLARG_H_"), "#define _BLARG_H_".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ @@ -299,17 +300,17 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { "blarg.h", h_file_code.indexOf("e _BLARG_H_") + 2, "_BLARG_H_".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ assertSoleFileLocation( macroDefinitions[2], - "blarg.h", h_file_code.indexOf("#define PRINT(s,m) printf(s,m)\r"), "#define PRINT(s,m) printf(s,m)".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + "blarg.h", h_file_code.indexOf("#define PRINT(s,m) printf(s,m)\r"), "#define PRINT(s,m) printf(s,m)".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ assertSoleFileLocation(macroDefinitions[2].getName(), - "blarg.h", h_file_code.indexOf("PRINT"), "PRINT".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + "blarg.h", h_file_code.indexOf("PRINT"), "PRINT".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ assertSoleFileLocation( macroDefinitions[3], filename, - c_file_code.indexOf("#define POST_INCLUDE"), "#define POST_INCLUDE".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + c_file_code.indexOf("#define POST_INCLUDE"), "#define POST_INCLUDE".length()); //$NON-NLS-1$ //$NON-NLS-2$ assertSoleFileLocation( macroDefinitions[3].getName(), filename, - c_file_code.indexOf("POST_INCLUDE"), "POST_INCLUDE".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + c_file_code.indexOf("POST_INCLUDE"), "POST_INCLUDE".length()); //$NON-NLS-1$ //$NON-NLS-2$ } } @@ -322,7 +323,7 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { for (ParserLanguage p : ParserLanguage.values()) { String filename = (p == ParserLanguage.CPP) ? "source.cc" : "source.c"; //$NON-NLS-1$ //$NON-NLS-2$ - IFile f = importFile(filename, cpp_code); //$NON-NLS-1$ + IFile f = importFile(filename, cpp_code); IASTTranslationUnit tu = parse(f); IASTDeclaration[] declarations = tu.getDeclarations(); IASTPreprocessorIncludeStatement[] includeDirectives = tu @@ -330,7 +331,7 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { assertSoleFileLocation( includeDirectives[0], filename, - cpp_code.indexOf("#include \"header1.h\""), "#include \"header1.h\"".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + cpp_code.indexOf("#include \"header1.h\""), "#include \"header1.h\"".length()); //$NON-NLS-1$ //$NON-NLS-2$ assertSoleFileLocation(declarations[0], "header1.h", 0, "int x;".length()); //$NON-NLS-1$ //$NON-NLS-2$ assertSoleFileLocation(declarations[1], @@ -338,9 +339,9 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { assertSoleFileLocation( includeDirectives[1], filename, - cpp_code.indexOf("#include \"header2.h\""), "#include \"header2.h\"".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + cpp_code.indexOf("#include \"header2.h\""), "#include \"header2.h\"".length()); //$NON-NLS-1$ //$NON-NLS-2$ assertSoleFileLocation(declarations[2], filename, cpp_code - .indexOf("int z;"), "int z;".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + .indexOf("int z;"), "int z;".length()); //$NON-NLS-1$ //$NON-NLS-2$ IASTTranslationUnit.IDependencyTree tree = tu.getDependencyTree(); assertEquals(tree.getInclusions().length, 2); @@ -357,8 +358,8 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { for (ParserLanguage p : ParserLanguage.values()) { String filename = (p == ParserLanguage.CPP) ? "blah.cc" : "blah.c"; //$NON-NLS-1$ //$NON-NLS-2$ - IFile c_file = importFile(filename, c_file_code); //$NON-NLS-1$ - IASTTranslationUnit tu = parse(c_file); //$NON-NLS-1$ + IFile c_file = importFile(filename, c_file_code); + IASTTranslationUnit tu = parse(c_file); assertEquals(tu.getDeclarations().length, 0); IASTPreprocessorMacroDefinition[] macroDefinitions = tu.getMacroDefinitions(); assertNotNull(macroDefinitions); @@ -366,9 +367,9 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { assertSoleFileLocation( macroDefinitions[0], filename, - c_file_code.indexOf("#define"), c_file_code.indexOf("4") + 1 - c_file_code.indexOf("#define")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + c_file_code.indexOf("#define"), c_file_code.indexOf("4") + 1 - c_file_code.indexOf("#define")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ assertSoleFileLocation(macroDefinitions[0].getName(), filename, - c_file_code.indexOf("X"), 1); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + c_file_code.indexOf("X"), 1); //$NON-NLS-1$ assertSoleFileLocation( macroDefinitions[1], "blarg.h", h_file_code.indexOf("#define _BLARG_H_"), "#define _BLARG_H_".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ @@ -377,24 +378,24 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { "blarg.h", h_file_code.indexOf("e _BLARG_H_") + 2, "_BLARG_H_".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ assertSoleFileLocation( macroDefinitions[2], - "blarg.h", h_file_code.indexOf("#define PRINT(s,m) printf(s,m)\r"), "#define PRINT(s,m) printf(s,m)".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + "blarg.h", h_file_code.indexOf("#define PRINT(s,m) printf(s,m)\r"), "#define PRINT(s,m) printf(s,m)".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ assertSoleFileLocation(macroDefinitions[2].getName(), - "blarg.h", h_file_code.indexOf("PRINT"), "PRINT".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + "blarg.h", h_file_code.indexOf("PRINT"), "PRINT".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ assertSoleFileLocation( macroDefinitions[3], filename, - c_file_code.indexOf("#define POST_INCLUDE"), "#define POST_INCLUDE".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + c_file_code.indexOf("#define POST_INCLUDE"), "#define POST_INCLUDE".length()); //$NON-NLS-1$ //$NON-NLS-2$ assertSoleFileLocation( macroDefinitions[3].getName(), filename, - c_file_code.indexOf("POST_INCLUDE"), "POST_INCLUDE".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + c_file_code.indexOf("POST_INCLUDE"), "POST_INCLUDE".length()); //$NON-NLS-1$ //$NON-NLS-2$ assertSoleFileLocation( macroDefinitions[4], "second.h", h_file2_code.indexOf("#define _SECOND_H_"), "#define _SECOND_H_".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ assertSoleFileLocation( macroDefinitions[5], filename, - c_file_code.indexOf("#define POST_SECOND"), "#define POST_SECOND".length()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + c_file_code.indexOf("#define POST_SECOND"), "#define POST_SECOND".length()); //$NON-NLS-1$ //$NON-NLS-2$ } } @@ -411,15 +412,15 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { buffer.append("};\n"); //$NON-NLS-1$ buffer.append("#endif /*_INCLUDE_H_*/\n"); //$NON-NLS-1$ final String inc_file_code = buffer.toString(); - IFile include_file = importFile("include.h", inc_file_code); //$NON-NLS-1$ //$NON-NLS-2$ + IFile include_file = importFile("include.h", inc_file_code); //$NON-NLS-1$ String[] macros = { imacro_file.getLocation().toOSString() }; String[] includes = { include_file.getLocation().toOSString() }; IExtendedScannerInfo scannerInfo = new ExtendedScannerInfo(Collections.EMPTY_MAP, EMPTY_STRING_ARRAY, macros, includes); for (ParserLanguage p : ParserLanguage.values()) { String filename = (p == ParserLanguage.CPP) ? "main.cc" : "main.c"; //$NON-NLS-1$ //$NON-NLS-2$ - IFile code = importFile(filename, "int main() { return BEAST * sizeof( Include ); } "); //$NON-NLS-1$ //$NON-NLS-2$ - IASTTranslationUnit tu = parse(code, scannerInfo); //$NON-NLS-1$ + IFile code = importFile(filename, "int main() { return BEAST * sizeof( Include ); } "); //$NON-NLS-1$ + IASTTranslationUnit tu = parse(code, scannerInfo); IASTPreprocessorMacroDefinition[] macro_defs = tu.getMacroDefinitions(); assertEquals(macro_defs.length, 2); IASTPreprocessorMacroDefinition BEAST = macro_defs[0]; @@ -443,8 +444,8 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { for (ParserLanguage p : ParserLanguage.values()) { String filename = (p == ParserLanguage.CPP) ? "blah.cc" : "blah.c"; //$NON-NLS-1$ //$NON-NLS-2$ - IFile f = importFile(filename, code); //$NON-NLS-1$ - IASTTranslationUnit tu = parse(f); //$NON-NLS-1$ + IFile f = importFile(filename, code); + IASTTranslationUnit tu = parse(f); IASTProblem[] prbs = tu.getPreprocessorProblems(); assertEquals(prbs.length, 1); IASTNodeLocation[] locs = prbs[0].getNodeLocations(); @@ -474,16 +475,16 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { buffer.append("};\n"); //$NON-NLS-1$ buffer.append("#endif /*_INCLUDE_H_*/\n"); //$NON-NLS-1$ final String inc_file_code = buffer.toString(); - IFile include_file = importFile("include.h", inc_file_code); //$NON-NLS-1$ //$NON-NLS-2$ + IFile include_file = importFile("include.h", inc_file_code); //$NON-NLS-1$ String[] macros = { imacro_file.getLocation().toOSString() }; String[] includes = { include_file.getLocation().toOSString() }; IExtendedScannerInfo scannerInfo = new ExtendedScannerInfo( Collections.EMPTY_MAP, EMPTY_STRING_ARRAY, macros, includes); for (ParserLanguage p : ParserLanguage.values()) { String filename = (p == ParserLanguage.CPP) ? "main.cc" : "main.c"; //$NON-NLS-1$ //$NON-NLS-2$ - IFile code = importFile(filename, "int main() { return BEAST * sizeof( Include ); } "); //$NON-NLS-1$ //$NON-NLS-2$ + IFile code = importFile(filename, "int main() { return BEAST * sizeof( Include ); } "); //$NON-NLS-1$ - IASTTranslationUnit tu = parse(code, scannerInfo); //$NON-NLS-1$ + IASTTranslationUnit tu = parse(code, scannerInfo); IASTPreprocessorMacroDefinition[] macro_defs = tu.getMacroDefinitions(); assertEquals(macro_defs.length, 4); IASTPreprocessorMacroDefinition BEAST = macro_defs[0]; @@ -515,14 +516,14 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { buffer.append("};\n"); //$NON-NLS-1$ buffer.append("#endif /*_INCLUDE_H_*/\n"); //$NON-NLS-1$ final String inc_file_code = buffer.toString(); - IFile include_file = importFile("include.h", inc_file_code); //$NON-NLS-1$ //$NON-NLS-2$ + IFile include_file = importFile("include.h", inc_file_code); //$NON-NLS-1$ String[] macros = { imacro_file1.getLocation().toOSString(), imacro_file2.getLocation().toOSString() }; String[] includes = { include_file.getLocation().toOSString() }; IExtendedScannerInfo scannerInfo = new ExtendedScannerInfo(Collections.EMPTY_MAP, EMPTY_STRING_ARRAY, macros, includes); for (ParserLanguage p : ParserLanguage.values()) { String filename = (p == ParserLanguage.CPP) ? "main.cc" : "main.c"; //$NON-NLS-1$ //$NON-NLS-2$ - IFile code = importFile(filename, "int main() { return BEAST * sizeof( Include ); } "); //$NON-NLS-1$ //$NON-NLS-2$ + IFile code = importFile(filename, "int main() { return BEAST * sizeof( Include ); } "); //$NON-NLS-1$ IASTTranslationUnit tu = parse(code, scannerInfo); IASTPreprocessorMacroDefinition[] macro_defs = tu.getMacroDefinitions(); @@ -611,4 +612,182 @@ public class DOMLocationInclusionTests extends AST2FileBasePluginTest { tmpFile.getParentFile().delete(); } } + + // // comment + // + // #ifndef guard + // #define guard + // bla bla + // #if 1 + // #endif + // bla bla + // #endif + // //comment + + // // comment + // + // #if !defined(guard) + // #define guard + // bla bla + // #if 1 + // #endif + // bla bla + // #endif + // //comment + + // // comment + // + // #if ((!defined guard)) + // #define guard + // bla bla + // #if 1 + // #endif + // bla bla + // #endif + // //comment + + // // comment + // #pragma once + + // // Some comment + // + // #ifndef AN_UNIQUE_INCLUDE_GUARD_H_ + // #define AN_UNIQUE_INCLUDE_GUARD_H_ + // + // #include + // + // Some code without any macro references + // + // #endif // AN_UNIQUE_INCLUDE_GUARD_H_ + public void testPragmaOnceDetection_197989a() throws Exception { + CharSequence[] contents= getContents(5); + + int i= 0; + for (CharSequence content : contents) { + String headerName = i + ".h"; + IFile base = importFile("base" + headerName, "#include \"" + headerName + "\""); + importFile(headerName, content.toString()); + IASTTranslationUnit tu = parse(base, new ScannerInfo()); + IASTPreprocessorIncludeStatement[] incs = tu.getIncludeDirectives(); + assertTrue(incs.length > 0); + assertTrue(incs[0].hasPragmaOnceSemantics()); + } + } + + // #ifndef guard + // #define guard2 + // #endif + + // #if !defined guard + // #define guard2 + // #endif + + // #if !defined(guard) && !defined(guard2) + // #define guard + // #endif + + // #if (0) + // #pragma once + // #endif + + // leading + // #ifndef guard + // #define guard2 + // #endif + + // #ifndef guard + // #define guard2 + // #endif + // #ifdef xx + // trailing + // #endif + public void testPragmaOnceDetection_197989b() throws Exception { + CharSequence[] contents= getContents(6); + + int i= 0; + for (CharSequence content : contents) { + String headerName = i + ".h"; + IFile base = importFile("base" + headerName, "#include \"" + headerName + "\""); + importFile(headerName, content.toString()); + IASTTranslationUnit tu = parse(base, new ScannerInfo()); + IASTPreprocessorIncludeStatement[] incs = tu.getIncludeDirectives(); + assertEquals(1, incs.length); + assertFalse(incs[0].hasPragmaOnceSemantics()); + } + } + + + // // header.h + // #ifdef AH + // #endif + // #ifndef BH + // #endif + // #define h + // #if CH || DH + // #elif EH==1 + // #endif + + // #define BH + // #define DH 0 + // #define EH 1 + // #include "header.h" + // #ifdef h // defined in header + // #endif + // #ifdef A + // #ifdef a // inactive + // #endif + // #else + // #ifndef B + // #endif + // #endif + // #if defined C + // #elif ((!((defined(D))))) + // #endif + // #define A + // #define B + // #define AH + // #define h + // #undef u + // #ifdef h // locally defined + // #endif + // #ifndef u // locally undefined + // #endif + public void testSignificantMacros_197989a() throws Exception { + CharSequence[] contents= getContents(2); + + IFile h = importFile("header.h", contents[0].toString()); + IFile c = importFile("source.c", contents[1].toString()); + + IASTTranslationUnit tu = parse(c, new ScannerInfo()); + IASTPreprocessorIncludeStatement[] incs = tu.getIncludeDirectives(); + assertEquals(1, incs.length); + assertEquals("{AH=null,BH=*,CH=null,DH=0,EH=1}", + incs[0].getSignificantMacros().toString()); + assertEquals("{A=null,AH=null,B=null,C=null,CH=null,D=null}", + tu.getSignificantMacros().toString()); + } + + // // header.h + // #if EQ(A,B) + // #endif + + // #define EQ(x,y) x==y + // #define A A1 + // #define B 1 + // #include "header.h" + public void testSignificantMacros_197989b() throws Exception { + CharSequence[] contents= getContents(2); + + IFile h = importFile("header.h", contents[0].toString()); + IFile c = importFile("source.c", contents[1].toString()); + + IASTTranslationUnit tu = parse(c, new ScannerInfo()); + IASTPreprocessorIncludeStatement[] incs = tu.getIncludeDirectives(); + assertEquals(1, incs.length); + assertEquals("{A=A1,A1=null,B=1,EQ=x==y}", + incs[0].getSignificantMacros().toString()); + assertEquals("{A1=null}", + tu.getSignificantMacros().toString()); + } + } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/FileCodeReaderFactory.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/FileCodeReaderFactory.java index 3668c5dcd15..b84db415e89 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/FileCodeReaderFactory.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/FileCodeReaderFactory.java @@ -1,29 +1,29 @@ /******************************************************************************* - * Copyright (c) 2004, 2009 IBM Corporation and others. + * Copyright (c) 2004, 2011 IBM Corporation 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 * * Contributors: - * IBM - Initial API and implementation + * IBM - Initial API and implementation *******************************************************************************/ package org.eclipse.cdt.core.parser.tests.scanner; import org.eclipse.cdt.core.index.IIndexFileLocation; import org.eclipse.cdt.core.parser.FileContent; +import org.eclipse.cdt.internal.core.parser.IMacroDictionary; import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContent; import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContentProvider; public class FileCodeReaderFactory extends InternalFileContentProvider { - private static FileCodeReaderFactory instance; private FileCodeReaderFactory() {} - @Override - public InternalFileContent getContentForInclusion(String path) { + public InternalFileContent getContentForInclusion(String path, + IMacroDictionary macroDictionary) { return (InternalFileContent) FileContent.createForExternalFileLocation(path); } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/LocationMapTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/LocationMapTests.java index 7b8fccea0d1..554f9fb10cb 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/LocationMapTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/LocationMapTests.java @@ -6,7 +6,7 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Markus Schorn - initial API and implementation + * Markus Schorn - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.core.parser.tests.scanner; @@ -37,10 +37,10 @@ import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorUndefStatement; import org.eclipse.cdt.core.dom.ast.IASTProblem; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; -import org.eclipse.cdt.core.dom.ast.IBinding; -import org.eclipse.cdt.core.dom.ast.IMacroBinding; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit.IDependencyTree; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit.IDependencyTree.IASTInclusionNode; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.IMacroBinding; import org.eclipse.cdt.core.testplugin.CTestPlugin; import org.eclipse.cdt.core.testplugin.util.BaseTestCase; import org.eclipse.cdt.core.testplugin.util.TestSourceReader; @@ -49,8 +49,8 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTranslationUnit; import org.eclipse.cdt.internal.core.parser.scanner.CharArray; import org.eclipse.cdt.internal.core.parser.scanner.ILocationCtx; import org.eclipse.cdt.internal.core.parser.scanner.ImageLocationInfo; -import org.eclipse.cdt.internal.core.parser.scanner.LocationMap; import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions; +import org.eclipse.cdt.internal.core.parser.scanner.LocationMap; public class LocationMapTests extends BaseTestCase { public class Loc implements IASTFileLocation { @@ -80,6 +80,9 @@ public class LocationMapTests extends BaseTestCase { public IASTFileLocation asFileLocation() { return this; } + public IASTPreprocessorIncludeStatement getContextInclusionStatement() { + return null; + } } private static final String FN = "filename"; @@ -336,8 +339,8 @@ public class LocationMapTests extends BaseTestCase { public void testIncludes() { init(DIGITS); - fLocationMap.encounterPoundInclude(0, 0, 0, 0, "n1".toCharArray(), null, true, false, false); - fLocationMap.encounterPoundInclude(0, 1, 3, 16, "n2".toCharArray(), "f2", false , true, false); + fLocationMap.encounterPoundInclude(0, 0, 0, 0, "n1".toCharArray(), null, true, false, false, null); + fLocationMap.encounterPoundInclude(0, 1, 3, 16, "n2".toCharArray(), "f2", false , true, false, null); IASTPreprocessorIncludeStatement[] includes= fLocationMap.getIncludeDirectives(); assertEquals(2, includes.length); checkInclude(includes[0], "", "", "n1", "", true, false, FN, 0, 0, 1, 0, 0); @@ -504,21 +507,21 @@ public class LocationMapTests extends BaseTestCase { ILocationCtx i2= fLocationMap.pushInclusion(6, 7, 8, 9, new CharArray("c1c2c3c4c5"), "pre11", "pre11".toCharArray(), false, false, false); assertEquals("pre11", fLocationMap.getCurrentFilePath()); fLocationMap.encounteredComment(2,6,true); - fLocationMap.popContext(i2); + fLocationMap.popContext(i2, null); // add a comment before the include fLocationMap.encounteredComment(4,6,false); assertEquals("pre1", fLocationMap.getCurrentFilePath()); - fLocationMap.popContext(i1); + fLocationMap.popContext(i1, null); assertEquals(FN, fLocationMap.getCurrentFilePath()); - fLocationMap.popContext(pre2); + fLocationMap.popContext(pre2, null); assertEquals(FN, fLocationMap.getCurrentFilePath()); // number [36, 46) ILocationCtx i3= fLocationMap.pushInclusion(0, 2, 4, 6, new CharArray("d1d2d3d4d5"), "pre2", "pre2".toCharArray(), false, false, false); assertEquals("pre2", fLocationMap.getCurrentFilePath()); fLocationMap.encounteredComment(0,2,true); - fLocationMap.popContext(i3); - fLocationMap.popContext(pre1); + fLocationMap.popContext(i3, null); + fLocationMap.popContext(pre1, null); assertEquals(FN, fLocationMap.getCurrentFilePath()); diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/EmptyIndexFragment.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/EmptyIndexFragment.java index 30d98de7f11..151109c0c80 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/EmptyIndexFragment.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/EmptyIndexFragment.java @@ -21,6 +21,7 @@ import org.eclipse.cdt.core.index.IIndexFileLocation; import org.eclipse.cdt.core.index.IIndexLinkage; import org.eclipse.cdt.core.index.IIndexMacro; import org.eclipse.cdt.core.index.IndexFilter; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.internal.core.index.IIndexFragment; import org.eclipse.cdt.internal.core.index.IIndexFragmentBinding; import org.eclipse.cdt.internal.core.index.IIndexFragmentFile; @@ -100,13 +101,24 @@ public class EmptyIndexFragment implements IIndexFragment { return 0; } + @Deprecated public IIndexFragmentFile getFile(int linkageID, IIndexFileLocation location) throws CoreException { return null; } + public IIndexFragmentFile getFile(int linkageID, IIndexFileLocation location, + ISignificantMacros sigMacros) throws CoreException { + return null; + } + + public IIndexFragmentFile[] getFiles(int linkageID, IIndexFileLocation location) + throws CoreException { + return IIndexFragmentFile.EMPTY_ARRAY; + } + public IIndexFragmentFile[] getFiles(IIndexFileLocation location) throws CoreException { - return new IIndexFragmentFile[0]; + return IIndexFragmentFile.EMPTY_ARRAY; } public long getLastWriteAccess() { diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBugsTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBugsTests.java index fd67979eb33..e5a1f740031 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBugsTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBugsTests.java @@ -1116,7 +1116,7 @@ public class IndexBugsTests extends BaseTestCase { // #endif // #ifndef _h1 - // #include "header1.h" + // #include "header1.h" // is inactive, but must be resolved, h1 is not significant // #endif // #include "header1.h" @@ -1127,7 +1127,7 @@ public class IndexBugsTests extends BaseTestCase { // #include "header2.h" // #ifndef _h1 - // #include "header1.h" + // #include "header1.h" // inactive and not resolved because header1.h is internally included. // #endif public void testIncludeGuardsOutsideOfHeader_Bug167100() throws Exception { final IIndexManager indexManager = CCorePlugin.getIndexManager(); @@ -1152,13 +1152,26 @@ public class IndexBugsTests extends BaseTestCase { assertEquals(1, names.length); assertEquals(f4.getFullPath().toString(), names[0].getFile().getLocation().getFullPath()); - IIndexFile idxFile= index.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(f5)); + IIndexFile[] idxFiles= index.getFiles(ILinkage.CPP_LINKAGE_ID, + IndexLocationFactory.getWorkspaceIFL(f2)); + assertEquals(1, idxFiles.length); + IIndexFile idxFile= idxFiles[0]; + IIndexInclude[] includes= idxFile.getIncludes(); + assertEquals(1, includes.length); + assertFalse(includes[0].isActive()); + assertTrue(includes[0].isResolved()); + assertEquals("{}", idxFile.getSignificantMacros().toString()); + + idxFiles= index.getFiles(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(f5)); + assertEquals(1, idxFiles.length); + idxFile= idxFiles[0]; + includes= idxFile.getIncludes(); assertEquals(2, includes.length); assertTrue(includes[0].isActive()); assertTrue(includes[0].isResolved()); assertFalse(includes[1].isActive()); - assertTrue(includes[1].isResolved()); + assertFalse(includes[1].isResolved()); } finally { index.releaseReadLock(); } @@ -1702,17 +1715,18 @@ public class IndexBugsTests extends BaseTestCase { // int aOK; // #endif /* A_H_ */ + // #ifndef B_H_ + // #define B_H_ // #ifndef A_H_ // #include "a.h" // #endif // - // #ifndef B_H_ - // #define B_H_ // int bOK; // #endif // #include "a.h" - public void testStrangeIncludeStrategy_Bug249884() throws Exception { + public void _testStrangeIncludeStrategy_Bug249884() throws Exception { + // TODO(197989) Should work again once the significant macro dictionary is used. String[] contents= getContentsForTest(3); final IIndexManager indexManager = CCorePlugin.getIndexManager(); IFile ah= TestSourceReader.createFile(fCProject.getProject(), "a.h", contents[0]); @@ -2423,4 +2437,4 @@ public class IndexBugsTests extends BaseTestCase { index.releaseReadLock(); } } -} \ No newline at end of file +} diff --git a/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/util/BaseTestCase.java b/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/util/BaseTestCase.java index d807643ba55..c9a74d91449 100644 --- a/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/util/BaseTestCase.java +++ b/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/util/BaseTestCase.java @@ -37,6 +37,7 @@ import org.eclipse.cdt.internal.core.CCoreInternals; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNameBase; import org.eclipse.cdt.internal.core.pdom.CModelListener; import org.eclipse.cdt.internal.core.pdom.PDOMManager; +import org.eclipse.cdt.internal.core.pdom.indexer.AbstractPDOMIndexer; import org.eclipse.core.resources.IResourceStatus; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.ILogListener; @@ -66,6 +67,7 @@ public class BaseTestCase extends TestCase { CPPASTNameBase.sAllowRecursionBindings= false; CPPASTNameBase.sAllowNameComputation= false; CModelListener.sSuppressUpdateOfLastRecentlyUsed= true; + AbstractPDOMIndexer.noFilesUpFront= true; } @Override @@ -294,4 +296,4 @@ public class BaseTestCase extends TestCase { } assertTrue(indexManager.joinIndexer(10000, npm())); } -} \ No newline at end of file +} diff --git a/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/util/TestSourceReader.java b/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/util/TestSourceReader.java index ce685b82fae..e9554a1cf77 100644 --- a/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/util/TestSourceReader.java +++ b/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/util/TestSourceReader.java @@ -286,12 +286,12 @@ public class TestSourceReader { Assert.assertTrue(CCorePlugin.getIndexManager().joinIndexer(timeLeft, new NullProgressMonitor())); index.acquireReadLock(); try { - IIndexFile pfile= index.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(file)); - if (pfile != null && pfile.getTimestamp() >= file.getLocalTimeStamp()) { + IIndexFile[] files= index.getFiles(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(file)); + if (files.length > 0 && areAllFilesNotOlderThan(files, file.getLocalTimeStamp())) { return; } - pfile= index.getFile(ILinkage.C_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(file)); - if (pfile != null && pfile.getTimestamp() >= file.getLocalTimeStamp()) { + files= index.getFiles(ILinkage.C_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(file)); + if (files.length > 0 && areAllFilesNotOlderThan(files, file.getLocalTimeStamp())) { return; } } finally { @@ -304,7 +304,16 @@ public class TestSourceReader { Assert.fail("Indexing " + file.getFullPath() + " did not complete in time!"); } - public static IASTTranslationUnit createIndexBasedAST(IIndex index, ICProject project, IFile file) throws CModelException, CoreException { + private static boolean areAllFilesNotOlderThan(IIndexFile[] files, long timestamp) throws CoreException { + for (IIndexFile file : files) { + if (file.getTimestamp() < timestamp) { + return false; + } + } + return true; + } + + public static IASTTranslationUnit createIndexBasedAST(IIndex index, ICProject project, IFile file) throws CModelException, CoreException { ICElement elem= project.findElement(file.getFullPath()); if (elem instanceof ITranslationUnit) { ITranslationUnit tu= (ITranslationUnit) elem; diff --git a/core/org.eclipse.cdt.core/.options b/core/org.eclipse.cdt.core/.options index 9f00de4f203..7b086655c64 100644 --- a/core/org.eclipse.cdt.core/.options +++ b/core/org.eclipse.cdt.core/.options @@ -12,6 +12,9 @@ org.eclipse.cdt.core/debug/parser/exceptions=false # Reports scanner activity org.eclipse.cdt.core/debug/scanner=false +# Reports scanner activity +org.eclipse.cdt.core/debug/scanner/missingIncludeGuards=false + # Reports search activity org.eclipse.cdt.core/debug/search=false diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/TranslationUnit.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/TranslationUnit.java index f57924b0116..32c3c394d0a 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/TranslationUnit.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/TranslationUnit.java @@ -839,30 +839,31 @@ public class TranslationUnit extends Openable implements ITranslationUnit { return fileContentsProvider; } - private static int[] CTX_LINKAGES= {ILinkage.CPP_LINKAGE_ID, ILinkage.C_LINKAGE_ID}; + private static final int[] CTX_LINKAGES= { ILinkage.CPP_LINKAGE_ID, ILinkage.C_LINKAGE_ID }; public ITranslationUnit getSourceContextTU(IIndex index, int style) { if (index != null && (style & AST_CONFIGURE_USING_SOURCE_CONTEXT) != 0) { try { fLanguageOfContext= null; - for (int element : CTX_LINKAGES) { + for (int linkageID : CTX_LINKAGES) { IIndexFile context= null; final IIndexFileLocation ifl = IndexLocationFactory.getIFL(this); if (ifl != null) { - IIndexFile indexFile= index.getFile(element, ifl); - if (indexFile != null) { - // bug 199412, when a source-file includes itself the context may recurse. - HashSet visited= new HashSet(); - visited.add(indexFile); - indexFile = getParsedInContext(indexFile); - while (indexFile != null && visited.add(indexFile)) { - context= indexFile; - indexFile= getParsedInContext(indexFile); + for (IIndexFile indexFile : index.getFiles(linkageID, ifl)) { + if (indexFile != null) { + // Bug 199412, when a source-file includes itself the context may recurse. + HashSet visited= new HashSet(); + visited.add(indexFile); + indexFile = getParsedInContext(indexFile); + while (indexFile != null && visited.add(indexFile)) { + context= indexFile; + indexFile= getParsedInContext(indexFile); + } } - } - if (context != null) { - ITranslationUnit tu= CoreModelUtil.findTranslationUnitForLocation(context.getLocation(), getCProject()); - if (tu != null && tu.isSourceUnit()) { - return tu; + if (context != null) { + ITranslationUnit tu= CoreModelUtil.findTranslationUnitForLocation(context.getLocation(), getCProject()); + if (tu != null && tu.isSourceUnit()) { + return tu; + } } } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTFileLocation.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTFileLocation.java index 7dd1462df02..f3a85ea5187 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTFileLocation.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTFileLocation.java @@ -50,4 +50,13 @@ public interface IASTFileLocation extends IASTNodeLocation { * @return int representing line number or 0 if not applicable */ public int getEndingLineNumber(); + + /** + * Returns the inclusion statement that included this file, or null for + * a top-level file. + * Also null when the file location does not belong to an AST node, e.g. + * if it is obtained from a name in the index. + * @since 5.4 + */ + public IASTPreprocessorIncludeStatement getContextInclusionStatement(); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTPreprocessorIncludeStatement.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTPreprocessorIncludeStatement.java index a1c8698ba66..48d87122e44 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTPreprocessorIncludeStatement.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTPreprocessorIncludeStatement.java @@ -6,20 +6,19 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * IBM - Initial API and implementation - * Markus Schorn (Wind River Systems) + * IBM - Initial API and implementation + * Markus Schorn (Wind River Systems) *******************************************************************************/ package org.eclipse.cdt.core.dom.ast; + /** * This interface represent a preprocessor #include statement. * * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ -public interface IASTPreprocessorIncludeStatement extends - IASTPreprocessorStatement { - +public interface IASTPreprocessorIncludeStatement extends IASTPreprocessorStatement, IFileNomination { /** * INCLUDE_NAME describes the relationship between an include directive and * it's name. diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTTranslationUnit.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTTranslationUnit.java index 3f467c197dd..3a7dfea8172 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTTranslationUnit.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTTranslationUnit.java @@ -16,6 +16,7 @@ import org.eclipse.cdt.core.dom.IName; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.core.parser.ParserLanguage; import org.eclipse.core.runtime.IAdaptable; @@ -28,7 +29,7 @@ import org.eclipse.core.runtime.IAdaptable; * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ -public interface IASTTranslationUnit extends IASTDeclarationListOwner, IAdaptable { +public interface IASTTranslationUnit extends IASTDeclarationListOwner, IFileNomination, IAdaptable { /** * OWNED_DECLARATION represents the relationship between an IASTTranslationUnit and @@ -343,4 +344,16 @@ public interface IASTTranslationUnit extends IASTDeclarationListOwner, IAdaptabl * @since 5.3 */ public ITranslationUnit getOriginatingTranslationUnit(); + + /** + * @since 5.4 + * @noreference This method is not intended to be referenced by clients. + */ + public void setSignificantMacros(ISignificantMacros sigMacros); + + /** + * @since 5.4 + * @noreference This method is not intended to be referenced by clients. + */ + public void setPragmaOnceSemantics(boolean value); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IFileNomination.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IFileNomination.java new file mode 100644 index 00000000000..ed11da90a6d --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IFileNomination.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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 + * + * Contributors: + * Markus Schorn - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.dom.ast; + +import org.eclipse.cdt.core.index.IIndexFile; +import org.eclipse.cdt.core.parser.ISignificantMacros; +import org.eclipse.core.runtime.CoreException; + +/** + * Interface for constructs that nominate a file for an AST: + * {@link IASTTranslationUnit}, {@link IASTPreprocessorIncludeStatement}, {@link IIndexFile}. + * @since 5.4 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IFileNomination { + /** + * Returns macros relevant to parsing of the file included by this include statement and their + * definitions at the point of the include. + *

+ * This method should only be called after the included file has been parsed. The method will + * return {@link ISignificantMacros#NONE} if it is called prematurely. + * @throws CoreException + */ + public ISignificantMacros getSignificantMacros() throws CoreException; + + /** + * Returns whether pragma once semantics has been detected when parsing the translation unit. + */ + public boolean hasPragmaOnceSemantics() throws CoreException; + + /** + * @return + */ + public boolean isComplete(); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java index ab4050b27fd..2f868eb12e3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java @@ -19,6 +19,7 @@ import java.util.regex.Pattern; import org.eclipse.cdt.core.dom.IName; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IScope; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; @@ -133,16 +134,53 @@ public interface IIndex { public long getLastWriteAccess(); /** - * Returns the file-object for the given location and linkage or returns - * null if the file was not indexed in this linkage. + * Returns the file object for the given location and linkage or null if the file + * was not indexed in this linkage. + *

+ * When a header file is stored in the index in multiple variants for different sets of macro + * definitions, this method will return an arbitrary one of these variants. * @param location an IIndexFileLocation representing the location of the file * @return the file in the index or null * @throws CoreException + * @deprecated Use {@link #getFile(int, IIndexFileLocation, ISignificantMacros)} or + * {@link #getFiles(int, IIndexFileLocation)}. */ + @Deprecated public IIndexFile getFile(int linkageID, IIndexFileLocation location) throws CoreException; /** - * Returns the file-objects for the given location in any linkage. + * Returns the file for the given location, linkage, and significant macros + * May return null, if no such file exists. + * + * @param linkageID the id of the linkage in which the file has been parsed. + * @param location the IIndexFileLocation representing the location of the file + * @param macroDictionary The names and definitions of the macros used to disambiguate between + * variants of the file contents corresponding to different inclusion points. + * @return the file for the location, or null if the file is not present in + * the index + * @throws CoreException + * @since 5.4 + */ + IIndexFile getFile(int linkageID, IIndexFileLocation location, ISignificantMacros significantMacros) + throws CoreException; + + /** + * Returns the file objects for the given location and linkage. + * Multiple files are returned when a header file is stored in the index in multiple variants + * for different sets of macro definitions. + * This method may only return files that are actually managed by this fragment. + * This method returns files without content, also. + * + * @param linkageID the id of the linkage in which the file has been parsed. + * @param location the IIndexFileLocation representing the location of the file + * @return the files for the location and the linkage. + * @throws CoreException + * @since 5.4 + */ + IIndexFile[] getFiles(int linkageID, IIndexFileLocation location) throws CoreException; + + /** + * Returns the file objects for the given location in any linkage. * @param location an IIndexFileLocation representing the location of the file * @return an array of file-objects. * @throws CoreException diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexFile.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexFile.java index a1cf9c71ee4..69ade650de2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexFile.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexFile.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2011 Wind River Systems, Inc. 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 @@ -8,10 +8,13 @@ * Contributors: * Markus Schorn - initial API and implementation * Andrew Ferguson (Symbian) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.core.index; +import org.eclipse.cdt.core.dom.ast.IFileNomination; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.core.runtime.CoreException; /** @@ -22,7 +25,7 @@ import org.eclipse.core.runtime.CoreException; * * @since 4.0 */ -public interface IIndexFile { +public interface IIndexFile extends IFileNomination { IIndexFile[] EMPTY_FILE_ARRAY = {}; /** @@ -32,6 +35,13 @@ public interface IIndexFile { */ IIndexFileLocation getLocation() throws CoreException; + /** + * Returns the significant macros for this version of the file. + * @throws CoreException + * @since 5.4 + */ + ISignificantMacros getSignificantMacros() throws CoreException; + /** * Returns all includes found in this file. * @return an array of all includes found in this file @@ -69,11 +79,9 @@ public interface IIndexFile { long getContentsHash() throws CoreException; /** - * Returns the hash-code of the scanner configuration that was used to parse the file. - * 0 will be returned in case the hash-code is unknown. - * @return the hash-code of the scanner configuration or 0. - * @throws CoreException + * @deprecated Returns 0. */ + @Deprecated int getScannerConfigurationHashcode() throws CoreException; /** @@ -93,7 +101,14 @@ public interface IIndexFile { * Returns the include that was used to parse this file, may be null. */ IIndexInclude getParsedInContext() throws CoreException; - + + /** + * Returns true if the file is a header with #pragma once statement or an include + * guard, or if it is a source file. + * @since 5.4 + */ + public boolean hasPragmaOnceSemantics() throws CoreException; + /** * Returns the id of the linkage this file was parsed in. * @since 5.0 diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexFileSet.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexFileSet.java index 1fff5b334fa..a30d8b1f34f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexFileSet.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexFileSet.java @@ -54,4 +54,10 @@ public interface IIndexFileSet { * @noreference This method is not intended to be referenced by clients. */ void add(IIndexFile indexFile); + + /** + * Removes a file from this set. + * @noreference This method is not intended to be referenced by clients. + */ + void remove(IIndexFile indexFile); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/AbstractParserLogService.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/AbstractParserLogService.java index f45f33486ed..64650e13a17 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/AbstractParserLogService.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/AbstractParserLogService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2008 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2011 Wind River Systems, Inc. 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 @@ -10,12 +10,39 @@ *******************************************************************************/ package org.eclipse.cdt.core.parser; + +import org.eclipse.cdt.internal.core.dom.parser.ParserLogServiceWrapper; public abstract class AbstractParserLogService implements IParserLogService { + /** + * @since 5.4 + */ + public static AbstractParserLogService convert(IParserLogService log) { + if (log instanceof AbstractParserLogService) + return (AbstractParserLogService) log; + return new ParserLogServiceWrapper(log); + } + public void traceLog(String message) { } + /** + * @param traceOption an option as defined in the .options file. + * @since 5.4 + */ + public boolean isTracing(String traceOption) { + return isTracing(); + } + + /** + * @param traceOption an option as defined in the .options file. + * @since 5.4 + */ + public void traceLog(String traceOption, String message) { + traceLog(message); + } + public void errorLog(String message) { } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IProblem.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IProblem.java index e521287347a..bd1ffc48c7c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IProblem.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IProblem.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2011 IBM Corporation 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 @@ -323,6 +323,12 @@ public interface IProblem */ public final static int PREPROCESSOR_POUND_WARNING = PREPROCESSOR_RELATED | 0x00E; + /** + * Maximum inclusion depth is exceeded + * @since 5.4 + */ + public final static int PREPROCESSOR_EXCEEDS_MAXIMUM_INCLUSION_DEPTH= PREPROCESSOR_RELATED | 0x00F; + /** * Syntax error, detected by the parser. */ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ISignificantMacros.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ISignificantMacros.java new file mode 100644 index 00000000000..1055359d157 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ISignificantMacros.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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 + * + * Contributors: + * Markus Schorn - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.parser; + +import org.eclipse.cdt.core.parser.util.CharArrayUtils; +import org.eclipse.cdt.internal.core.parser.scanner.SignificantMacros; + +/** + * Significant macros describe the conditions under which the preprocessor selects + * the same active code branches in a file. + * @since 5.4 + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ISignificantMacros { + interface IVisitor { + /** + * Returns whether to continue the visit. + */ + boolean visitDefined(char[] macro); + + /** + * Returns whether to continue the visit. + */ + boolean visitUndefined(char[] macro); + + /** + * Returns whether to continue the visit. + */ + boolean visitValue(char[] macro, char[] value); + + /** + * Returns whether to continue the visit. + */ + boolean visitIncluded(char[] path); + } + + ISignificantMacros NONE = new SignificantMacros(CharArrayUtils.EMPTY); + + /** + * Returns whether visitor continued its visit till the end. + */ + boolean accept(IVisitor visitor); + + /** + * Returns the significant macros encoded as an array of characters. + */ + char[] encode(); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CharArrayObjectMap.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CharArrayObjectMap.java index 35fba211343..3f120cd7fed 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CharArrayObjectMap.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CharArrayObjectMap.java @@ -19,8 +19,8 @@ import java.util.List; /** * @author Doug Schaefer */ -public class CharArrayObjectMap extends CharTable { - public static final CharArrayObjectMap EMPTY_MAP = new CharArrayObjectMap(0) { +public class CharArrayObjectMap extends CharTable { + public static final CharArrayObjectMap EMPTY_MAP = new CharArrayObjectMap(0) { @Override public Object clone() { return this; } @Override @@ -30,6 +30,14 @@ public class CharArrayObjectMap extends CharTable { throw new UnsupportedOperationException(); } }; + /** + * @since 5.4 + */ + @SuppressWarnings("unchecked") + public static CharArrayObjectMap emptyMap() { + return (CharArrayObjectMap) EMPTY_MAP; + } + private Object[] valueTable; @@ -38,40 +46,44 @@ public class CharArrayObjectMap extends CharTable { valueTable = new Object[capacity()]; } - public Object put(char[] key, int start, int length, Object value) { + public T put(char[] key, int start, int length, T value) { int i = addIndex(key, start, length); - Object oldvalue = valueTable[i]; + @SuppressWarnings("unchecked") + T oldvalue = (T) valueTable[i]; valueTable[i] = value; return oldvalue; } - final public Object put(char[] key, Object value) { + final public T put(char[] key, T value) { return put(key, 0, key.length, value); } - final public Object get(char[] key, int start, int length) { + @SuppressWarnings("unchecked") + final public T get(char[] key, int start, int length) { int i = lookup(key, start, length); if (i >= 0) - return valueTable[i]; + return (T) valueTable[i]; return null; } - final public Object get(char[] key) { + final public T get(char[] key) { return get(key, 0, key.length); } - final public Object getAt(int i) { + @SuppressWarnings("unchecked") + final public T getAt(int i) { if (i < 0 || i > currEntry) return null; - return valueTable[i]; + return (T) valueTable[i]; } - final public Object remove(char[] key, int start, int length) { + final public T remove(char[] key, int start, int length) { int i = lookup(key, start, length); if (i < 0) return null; - Object value = valueTable[i]; + @SuppressWarnings("unchecked") + T value = (T) valueTable[i]; if (i < currEntry) System.arraycopy(valueTable, i + 1, valueTable, i, currEntry - i); @@ -85,7 +97,8 @@ public class CharArrayObjectMap extends CharTable { @Override public Object clone() { - CharArrayObjectMap newTable = (CharArrayObjectMap) super.clone(); + @SuppressWarnings("unchecked") + CharArrayObjectMap newTable = (CharArrayObjectMap) super.clone(); newTable.valueTable = new Object[capacity()]; System.arraycopy(valueTable, 0, newTable.valueTable, 0, valueTable.length); @@ -149,4 +162,5 @@ public class CharArrayObjectMap extends CharTable { System.arraycopy(valueTable, 0, values, 0, values.length); return values; } + } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTInternal.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTInternal.java index e4cfb2ef56d..866a55bf964 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTInternal.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTInternal.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2011 Wind River Systems, Inc. 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 @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser; +import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IBinding; @@ -71,7 +72,7 @@ public class ASTInternal { } } - public static String getDeclaredInSourceFileOnly(IBinding binding, boolean requireDefinition, PDOMBinding nonLocal) { + public static IASTNode getDeclaredInSourceFileOnly(IBinding binding, boolean requireDefinition, PDOMBinding nonLocal) { IASTNode[] decls; IASTNode def; if (binding instanceof ICPPInternalBinding) { @@ -88,18 +89,19 @@ public class ASTInternal { if (requireDefinition && def == null) { return null; } - String filePath= null; + IASTNode result= null; if (def != null) { - if ((filePath= isPartOfSource(filePath, def)) == null) { + if (!isPartOfSource(def)) return null; - } + result= def; } if (decls != null) { for (final IASTNode node : decls) { if (node != null) { - if ((filePath= isPartOfSource(filePath, node)) == null) { + if (!isPartOfSource(node)) + return null; + if ((result= resolveConflict(result, node)) == null) return null; - } } } } @@ -110,23 +112,29 @@ public class ASTInternal { } catch (CoreException e) { } } - return filePath; + return result; } - private static String isPartOfSource(String filePath, IASTNode decl) { - if (decl instanceof ASTNode) { - if (((ASTNode) decl).isPartOfSourceFile()) { - if (filePath == null) - return decl.getContainingFilename(); - - if (filePath.equals(decl.getContainingFilename())) - return filePath; - } - } - return null; + private static boolean isPartOfSource(IASTNode decl) { + return decl instanceof ASTNode && ((ASTNode) decl).isPartOfSourceFile(); } - public static String getDeclaredInOneFileOnly(IBinding binding) { + private static IASTNode resolveConflict(IASTNode n1, IASTNode n2) { + if (n1 == null) + return n2; + + IASTFileLocation loc1= n1.getFileLocation(); + if (loc1 == null) + return n2; + + IASTFileLocation loc2= n2.getFileLocation(); + if (loc2 != null && loc1.getContextInclusionStatement() != loc2.getContextInclusionStatement()) + return null; + + return n1; + } + + public static IASTNode getDeclaredInOneFileOnly(IBinding binding) { IASTNode[] decls; IASTNode def; if (binding instanceof ICPPInternalBinding) { @@ -140,23 +148,19 @@ public class ASTInternal { } else { return null; } - String filePath= null; + IASTNode result= null; if (def != null) { - filePath= def.getContainingFilename(); + result= def; } if (decls != null) { for (final IASTNode node : decls) { if (node != null) { - final String fn = node.getContainingFilename(); - if (filePath == null) { - filePath= fn; - } else if (!filePath.equals(fn)) { + if ((result= resolveConflict(result, node)) == null) return null; - } } } } - return filePath; + return result; } public static void addDeclaration(IBinding b, IASTNode declaration) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java index 63d2265bc31..f338429b4cf 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java @@ -37,6 +37,7 @@ import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexFile; import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.internal.core.index.IndexBasedFileContentProvider; import org.eclipse.cdt.internal.core.parser.scanner.ILocationResolver; @@ -71,6 +72,10 @@ public abstract class ASTTranslationUnit extends ASTNode implements IASTTranslat private INodeFactory fNodeFactory; private boolean fForContentAssist; private ITranslationUnit fOriginatingTranslationUnit; + private ISignificantMacros fSignificantMacros= ISignificantMacros.NONE; + private boolean fPragmaOnceSemantics; + private boolean fComplete; + /** The semaphore controlling exclusive access to the AST. */ private final Semaphore fSemaphore= new Semaphore(1); @@ -367,6 +372,7 @@ public abstract class ASTTranslationUnit extends ASTNode implements IASTTranslat if (fIndexFileSet != null) { List files= fileContent.getFilesIncluded(); for (IIndexFile indexFile : files) { + fASTFileSet.remove(indexFile); fIndexFileSet.add(indexFile); } } @@ -376,13 +382,14 @@ public abstract class ASTTranslationUnit extends ASTNode implements IASTTranslat return fIndexFileSet; } - public void replacingFile(InternalFileContentProvider provider, InternalFileContent fc) { + public void parsingFile(InternalFileContentProvider provider, InternalFileContent fc) { if (fASTFileSet != null) { if (provider instanceof IndexBasedFileContentProvider) { try { - IIndexFile file= ((IndexBasedFileContentProvider) provider).findIndexFile(fc); - if (file != null) { - fASTFileSet.add(file); + for (IIndexFile file : ((IndexBasedFileContentProvider) provider).findIndexFiles(fc)) { + if (!fIndexFileSet.contains(file)) { + fASTFileSet.add(file); + } } } catch (CoreException e) { // Ignore, tracking of replaced files fails. @@ -450,6 +457,30 @@ public abstract class ASTTranslationUnit extends ASTNode implements IASTTranslat this.fOriginatingTranslationUnit = tu; } + public ISignificantMacros getSignificantMacros() { + return fSignificantMacros; + } + + public void setSignificantMacros(ISignificantMacros sigMacros) { + assertNotFrozen(); + if (sigMacros != null) + fSignificantMacros= sigMacros; + fComplete= true; + } + + public boolean hasPragmaOnceSemantics() { + return fPragmaOnceSemantics; + } + + public void setPragmaOnceSemantics(boolean value) { + assertNotFrozen(); + fPragmaOnceSemantics= value; + } + + public boolean isComplete() { + return fComplete; + } + /** * Starts exclusive access * @throws InterruptedException diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java index 8baba365940..54e46eacea2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java @@ -200,7 +200,6 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { private final INodeFactory nodeFactory; private boolean fActiveCode= true; - private int fEndOffset= -1; protected AbstractGNUSourceCodeParser(IScanner scanner, IParserLogService logService, ParserMode parserMode, @@ -435,7 +434,6 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { try { return LA(i); } catch (EndOfFileException e) { - fEndOffset= e.getEndOffset(); return null; } } @@ -456,7 +454,6 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { try { return LT(i); } catch (EndOfFileException e) { - fEndOffset= e.getEndOffset(); return 0; } } @@ -1281,9 +1278,6 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { protected void parseTranslationUnit() { final IASTTranslationUnit tu= getTranslationUnit(); declarationList(tu, DeclarationOptions.GLOBAL, false, 0); - // Bug 3033152: getEndOffset() is computed off the last node and ignores trailing macros. - final int length= Math.max(getEndOffset(), fEndOffset); - ((ASTNode) tu).setLength(length); } protected final void declarationListInBraces(final IASTDeclarationListOwner tu, int offset, DeclarationOptions options) throws EndOfFileException, BacktrackException { @@ -1356,7 +1350,6 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { IASTDeclaration declaration= skipProblemDeclaration(offset); addDeclaration(tu, declaration, active); if (!e.endsInactiveCode()) { - fEndOffset= e.getEndOffset(); break; } } finally { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java index 03346097b98..d80a85d3c36 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java @@ -227,7 +227,7 @@ public class TemplateArgumentDeduction { ICPPTemplateInstance pInst = (ICPPTemplateInstance) pcheck; ICPPClassTemplate pTemplate= getPrimaryTemplate(pInst); if (pTemplate != null) { - ICPPClassType aInst= findBaseInstance((ICPPClassType) argcheck, pTemplate, CPPSemantics.MAX_INHERITANCE_DEPTH); + ICPPClassType aInst= findBaseInstance((ICPPClassType) argcheck, pTemplate); if (aInst != null && aInst != argcheck) { par= pcheck; arg= aInst; @@ -467,10 +467,15 @@ public class TemplateArgumentDeduction { return result.toArray(new ICPPTemplateArgument[result.size()]); } + /** * 14.8.2.1.3 If P is a class and has the form template-id, then A can be a derived class of the deduced A. */ - private static ICPPClassType findBaseInstance(ICPPClassType a, ICPPClassTemplate pTemplate, int maxdepth) throws DOMException { + private static ICPPClassType findBaseInstance(ICPPClassType a, ICPPClassTemplate pTemplate) throws DOMException { + return findBaseInstance(a, pTemplate, CPPSemantics.MAX_INHERITANCE_DEPTH, new HashSet()); + } + + private static ICPPClassType findBaseInstance(ICPPClassType a, ICPPClassTemplate pTemplate, int maxdepth, HashSet handled) throws DOMException { if (a instanceof ICPPTemplateInstance) { final ICPPTemplateInstance inst = (ICPPTemplateInstance) a; ICPPClassTemplate tmpl= getPrimaryTemplate(inst); @@ -480,8 +485,8 @@ public class TemplateArgumentDeduction { if (maxdepth-- > 0) { for (ICPPBase cppBase : a.getBases()) { IBinding base= cppBase.getBaseClass(); - if (base instanceof ICPPClassType) { - final ICPPClassType inst= findBaseInstance((ICPPClassType) base, pTemplate, maxdepth); + if (base instanceof ICPPClassType && handled.add(base)) { + final ICPPClassType inst= findBaseInstance((ICPPClassType) base, pTemplate, maxdepth, handled); if (inst != null) return inst; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/CIndex.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/CIndex.java index c5907a0da4e..c02d7230f7b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/CIndex.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/CIndex.java @@ -17,13 +17,13 @@ package org.eclipse.cdt.internal.core.index; import java.util.ArrayList; import java.util.Arrays; -import java.util.BitSet; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Set; import java.util.regex.Pattern; import org.eclipse.cdt.core.CCorePlugin; @@ -42,6 +42,7 @@ import org.eclipse.cdt.core.index.IIndexInclude; import org.eclipse.cdt.core.index.IIndexMacro; import org.eclipse.cdt.core.index.IIndexName; import org.eclipse.cdt.core.index.IndexFilter; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.internal.core.dom.Linkage; import org.eclipse.cdt.internal.core.index.composite.CompositingNotImplementedError; import org.eclipse.cdt.internal.core.index.composite.ICompositesFactory; @@ -208,6 +209,7 @@ public class CIndex implements IIndex { return findNames(binding, FIND_REFERENCES); } + @Deprecated public IIndexFile getFile(int linkageID, IIndexFileLocation location) throws CoreException { for (int i = 0; i < fPrimaryFragmentCount; i++) { IIndexFragmentFile candidate= fFragments[i].getFile(linkageID, location); @@ -218,19 +220,53 @@ public class CIndex implements IIndex { return null; } + public IIndexFile getFile(int linkageID, IIndexFileLocation location, + ISignificantMacros significantMacros) throws CoreException { + for (int i = 0; i < fPrimaryFragmentCount; i++) { + IIndexFragmentFile candidate= fFragments[i].getFile(linkageID, location, significantMacros); + if (candidate != null && candidate.hasContent()) { + return candidate; + } + } + return null; + } + + public IIndexFile[] getFiles(int linkageID, IIndexFileLocation location) throws CoreException { + if (location == null) { + return IIndexFile.EMPTY_FILE_ARRAY; + } + Set handled = new HashSet(); + ArrayList result= new ArrayList(); + for (int i = 0; i < fPrimaryFragmentCount; i++) { + IIndexFragmentFile[] candidates= fFragments[i].getFiles(linkageID, location); + for (IIndexFragmentFile candidate : candidates) { + if (candidate.hasContent()) { + ISignificantMacros macroKey = candidate.getSignificantMacros(); + if (handled.add(macroKey)) { + result.add(candidate); + } + } + } + } + if (result.isEmpty()) { + return IIndexFile.EMPTY_FILE_ARRAY; + } + return result.toArray(new IIndexFile[result.size()]); + } + public IIndexFile[] getFiles(IIndexFileLocation location) throws CoreException { if (location == null) { return IIndexFile.EMPTY_FILE_ARRAY; } + Set keys = new HashSet(); ArrayList result= new ArrayList(); - BitSet linkages= new BitSet(); for (int i = 0; i < fPrimaryFragmentCount; i++) { IIndexFragmentFile[] candidates= fFragments[i].getFiles(location); for (IIndexFragmentFile candidate : candidates) { - int linkage= candidate.getLinkageID(); - if (!linkages.get(linkage) && candidate.hasContent()) { - result.add(candidate); - linkages.set(linkage); + if (candidate.hasContent()) { + if (keys.add(new FileContentKey(candidate.getLinkageID(), candidate.getLocation(), candidate.getSignificantMacros()))) { + result.add(candidate); + } } } } @@ -241,16 +277,16 @@ public class CIndex implements IIndex { } public IIndexFile resolveInclude(IIndexInclude include) throws CoreException { - if (!include.isResolved()) { - return null; - } IIndexFragmentInclude fragmentInclude = (IIndexFragmentInclude) include; IIndexFragmentFile result= fragmentInclude.getIncludes(); - if (result != null && result.hasContent()) { + if (result == null) + return null; + + if (result.hasContent()) { return result; } - return getFile(include.getIncludedBy().getLinkageID(), include.getIncludesLocation()); + return getFile(result.getLinkageID(), result.getLocation(), result.getSignificantMacros()); } public IIndexInclude[] findIncludedBy(IIndexFile file) throws CoreException { @@ -289,7 +325,6 @@ public class CIndex implements IIndex { findIncludedBy(nextLevel, out, depth, handled); } - public IIndexInclude[] findIncludes(IIndexFile file) throws CoreException { return findIncludes(file, 0); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/EmptyCIndex.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/EmptyCIndex.java index eb522b54d30..acc91a98edc 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/EmptyCIndex.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/EmptyCIndex.java @@ -29,6 +29,7 @@ import org.eclipse.cdt.core.index.IIndexInclude; import org.eclipse.cdt.core.index.IIndexMacro; import org.eclipse.cdt.core.index.IIndexName; import org.eclipse.cdt.core.index.IndexFilter; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; @@ -54,10 +55,20 @@ final public class EmptyCIndex implements IIndex { return IIndexFragmentName.EMPTY_NAME_ARRAY; } + @Deprecated public IIndexFile getFile(int linkageID, IIndexFileLocation location) { return null; } + public IIndexFile getFile(int linkageID, IIndexFileLocation location, + ISignificantMacros significantFiles) throws CoreException { + return null; + } + + public IIndexFile[] getFiles(int linkageID, IIndexFileLocation location) throws CoreException { + return IIndexFile.EMPTY_FILE_ARRAY; + } + public IIndexFile[] getFiles(IIndexFileLocation location) { return IIndexFile.EMPTY_FILE_ARRAY; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/FileContentKey.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/FileContentKey.java new file mode 100644 index 00000000000..2c6b9d327e9 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/FileContentKey.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2011 Google, Inc 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 + * + * Contributors: + * Sergey Prigogin (Google) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.core.index; + +import org.eclipse.cdt.core.index.IIndexFileLocation; +import org.eclipse.cdt.core.parser.ISignificantMacros; + +/** + * A key that uniquely determines the preprocessed contents of a file. + */ +public class FileContentKey { + private final int linkageID; + private final IIndexFileLocation location; + private final ISignificantMacros significantMacros; + + /** + * Creates a file content key. + * @param location the file location. + */ + public FileContentKey(int linkageID, IIndexFileLocation location, ISignificantMacros sigMacros) { + this.linkageID= linkageID; + this.location = location; + this.significantMacros = sigMacros; + } + + public int getLinkageID() { + return linkageID; + } + + public IIndexFileLocation getLocation() { + return location; + } + + public ISignificantMacros getSignificantMacros() { + return significantMacros; + } + + @Override + public int hashCode() { + return (linkageID + location.hashCode() * 31) * 31 + significantMacros.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + FileContentKey other = (FileContentKey) obj; + if (linkageID != other.linkageID) + return false; + + if (!location.equals(other.location)) + return false; + + if (!significantMacros.equals(other.significantMacros)) + return false; + + return true; + } + + @SuppressWarnings("nls") + @Override + public String toString() { + return linkageID + ": " + location.getURI().toString() + "[" + significantMacros.hashCode() + "]"; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragment.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragment.java index 42895d8d79b..3675ce5ed57 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragment.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragment.java @@ -23,6 +23,7 @@ import org.eclipse.cdt.core.index.IIndexFileLocation; import org.eclipse.cdt.core.index.IIndexLinkage; import org.eclipse.cdt.core.index.IIndexMacro; import org.eclipse.cdt.core.index.IndexFilter; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; @@ -92,14 +93,55 @@ public interface IIndexFragment { * May return null, if no such file exists. * This method may only return files that are actually managed by this fragment. * This method returns files without content, also. + *

+ * When a header file is stored in the index in multiple variants for different sets of macro + * definitions, this method will return an arbitrary one of these variants. + * * @param linkageID the id of the linkage in which the file has been parsed. * @param location the IIndexFileLocation representing the location of the file * @return the file for the location, or null if the file is not present in * the index * @throws CoreException + * @deprecated Use {@link #getFile(int, IIndexFileLocation, ISignificantMacros)} or + * {@link #getFiles(int, IIndexFileLocation)}. */ + @Deprecated IIndexFragmentFile getFile(int linkageID, IIndexFileLocation location) throws CoreException; + /** + * Returns the file for the given location, linkage, and a set of macro definitions. + * May return null, if no such file exists. + * This method may only return files that are actually managed by this fragment. + * This method returns files without content, also. + * + * @param linkageID the id of the linkage in which the file has been parsed. + * @param location the IIndexFileLocation representing the location of the file + * @param macroDictionary The names and definitions of the macros used to disambiguate between + * variants of the file contents corresponding to different inclusion points. + * @return the file for the location, or null if the file is not present in + * the index + * @throws CoreException + */ + IIndexFragmentFile getFile(int linkageID, IIndexFileLocation location, + ISignificantMacros significantMacros) throws CoreException; + + /** + * Returns the files for the given location and linkage. + * Multiple files are returned when a header file is stored in the index in multiple variants + * for different sets of macro definitions. + * This method may only return files that are actually managed by this fragment. + * This method returns files without content, also. + *

+ * When a header file is stored in the index in multiple variants for different sets of macro + * definitions, this method will return an arbitrary one of these variants. + * + * @param linkageID the id of the linkage in which the file has been parsed. + * @param location the IIndexFileLocation representing the location of the file + * @return the files for the location and the linkage. + * @throws CoreException + */ + IIndexFragmentFile[] getFiles(int linkageID, IIndexFileLocation location) throws CoreException; + /** * Returns the files in all linkages for the given location. * This method may only return files that are actually managed by this fragment. diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragmentFile.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragmentFile.java index 887133feb52..ae48b5a6cae 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragmentFile.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragmentFile.java @@ -1,15 +1,15 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2011 Wind River Systems, Inc. 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 * * Contributors: - * Markus Schorn - initial API and implementation - * Andrew Ferguson (Symbian) + * Markus Schorn - initial API and implementation + * Andrew Ferguson (Symbian) + * Sergey Prigogin (Google) *******************************************************************************/ - package org.eclipse.cdt.internal.core.index; import org.eclipse.cdt.core.index.IIndexFile; @@ -33,19 +33,18 @@ public interface IIndexFragmentFile extends IIndexFile { */ void setContentsHash(long hash) throws CoreException; - /** - * Sets the hash-code of the scanner configuration. - * @param hashcode a hash-code or 0 if it is unknown. - * @throws CoreException - */ - void setScannerConfigurationHashcode(int hashcode) throws CoreException; - /** * Sets the hash-code of the file encoding. * @param hashcode a hash-code or 0 if it is unknown. */ void setEncodingHashcode(int hashcode) throws CoreException; + /** + * Sets the flag that determines whether the file is a header with #pragma once statement + * or an include guard, or it is a source file and parsed only once because of that. + */ + void setPragmaOnceSemantics(boolean value) throws CoreException; + /** * Returns whether this file contains content in its * associated fragment. Files without content are inserted to track includes. diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragmentFileSet.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragmentFileSet.java index 39eeb9d38bf..bfe5d1ed5cb 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragmentFileSet.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragmentFileSet.java @@ -25,6 +25,11 @@ public interface IIndexFragmentFileSet { */ void add(IIndexFragmentFile fragFile); + /** + * Removes the fragment file from the file-set. + */ + void remove(IIndexFragmentFile fragFile); + /** * Returns whether the file set contains the given file. */ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IWritableIndex.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IWritableIndex.java index b2fd477791d..bac8d3bb737 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IWritableIndex.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IWritableIndex.java @@ -6,9 +6,9 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Markus Schorn - initial API and implementation - * Andrew Ferguson (Symbian) - * Sergey Prigogin (Google) + * Markus Schorn - initial API and implementation + * Andrew Ferguson (Symbian) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.index; @@ -20,6 +20,7 @@ import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexFile; import org.eclipse.cdt.core.index.IIndexFileLocation; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.internal.core.pdom.ASTFilePathResolver; import org.eclipse.cdt.internal.core.pdom.YieldableIndexLock; import org.eclipse.core.runtime.CoreException; @@ -45,14 +46,15 @@ public interface IWritableIndex extends IIndex { boolean isWritableFile(IIndexFile file); /** - * Returns a writable file for the given location and linkage, or null. This method - * returns file-objects without content, also. + * Returns a writable file for the given location, linkage, and the set of macro definitions, + * or null. This method returns file objects without content, also. */ - IIndexFragmentFile getWritableFile(int linkageID, IIndexFileLocation location) throws CoreException; + IIndexFragmentFile getWritableFile(int linkageID, IIndexFileLocation location, + ISignificantMacros macroDictionary) throws CoreException; /** * Returns the writable files for the given location in any linkage. This method - * returns file-objects without content, also. + * returns file objects without content, also. */ IIndexFragmentFile[] getWritableFiles(IIndexFileLocation location) throws CoreException; @@ -66,17 +68,24 @@ public interface IWritableIndex extends IIndex { /** * Creates a file object for the given location or returns an existing one. + * @param linkageID the id of the linkage in which the file has been parsed. + * @param location the IIndexFileLocation representing the location of the file + * @param macroDictionary The names and definitions of the macros used to disambiguate between + * variants of the file contents corresponding to different inclusion points. + * @return A created or an existing file. */ - IIndexFragmentFile addFile(int linkageID, IIndexFileLocation location) throws CoreException; + IIndexFragmentFile addFile(int linkageID, IIndexFileLocation location, + ISignificantMacros macroDictionary) throws CoreException; /** * Creates a uncommitted file object for the given location. */ - IIndexFragmentFile addUncommittedFile(int linkageID, IIndexFileLocation location) throws CoreException; + IIndexFragmentFile addUncommittedFile(int linkageID, IIndexFileLocation location, + ISignificantMacros macroDictionary) throws CoreException; /** * Makes an uncommitted file that was created earlier by calling - * {@link #addUncommittedFile(int, IIndexFileLocation)} method visible in the index. + * {@link #addUncommittedFile(int, IIndexFileLocation, ISignificantMacros)} method visible in the index. * * @return The file that was updated. * @throws CoreException diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IWritableIndexFragment.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IWritableIndexFragment.java index 5aeea79d6d9..80a17246883 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IWritableIndexFragment.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IWritableIndexFragment.java @@ -6,9 +6,9 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Markus Schorn - initial API and implementation - * Andrew Ferguson (Symbian) - * Sergey Prigogin (Google) + * Markus Schorn - initial API and implementation + * Andrew Ferguson (Symbian) + * Sergey Prigogin (Google) ******************************************************************************/ package org.eclipse.cdt.internal.core.index; @@ -18,6 +18,7 @@ import java.util.Collection; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement; import org.eclipse.cdt.core.index.IIndexFileLocation; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.internal.core.index.IWritableIndex.IncludeInformation; import org.eclipse.cdt.internal.core.pdom.ASTFilePathResolver; import org.eclipse.cdt.internal.core.pdom.YieldableIndexLock; @@ -44,23 +45,27 @@ public interface IWritableIndexFragment extends IIndexFragment { /** * Creates a file object for the given location and linkage or returns an existing one. * @param fileLocation an IIndexFileLocation representing the location of the file. + * @param sigMacros the macro definitions at the inclusion point. * @return the existing IIndexFragmentFile for this location, or a newly created one. * @throws CoreException */ - IIndexFragmentFile addFile(int linkageID, IIndexFileLocation fileLocation) throws CoreException; + IIndexFragmentFile addFile(int linkageID, IIndexFileLocation fileLocation, + ISignificantMacros sigMacros) throws CoreException; /** * Creates a file object for the given location and linkage. The created file object is not added to * the file index. * @param fileLocation an IIndexFileLocation representing the location of the file. + * @param sigMacros the macro definitions at the inclusion point. * @return a newly created IIndexFragmentFile. * @throws CoreException */ - IIndexFragmentFile addUncommittedFile(int linkageID, IIndexFileLocation fileLocation) throws CoreException; + IIndexFragmentFile addUncommittedFile(int linkageID, IIndexFileLocation fileLocation, + ISignificantMacros sigMacros) throws CoreException; /** * Makes an uncommitted file that was created earlier by calling - * {@link #addUncommittedFile(int, IIndexFileLocation)} method visible in the index. + * {@link #addUncommittedFile(int, IIndexFileLocation, ISignificantMacros)} method visible in the index. * * @return The file that was updated. * @throws CoreException diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IndexBasedFileContentProvider.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IndexBasedFileContentProvider.java index b08259e370c..59ef5536410 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IndexBasedFileContentProvider.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IndexBasedFileContentProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2010 QNX Software Systems and others. + * Copyright (c) 2005, 2011 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 @@ -11,16 +11,20 @@ * Andrew Ferguson (Symbian) * Anton Leherbauer (Wind River Systems) * IBM Corporation + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.index; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.ast.IFileNomination; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexFile; @@ -28,6 +32,7 @@ import org.eclipse.cdt.core.index.IIndexFileLocation; import org.eclipse.cdt.core.index.IIndexInclude; import org.eclipse.cdt.core.index.IIndexMacro; import org.eclipse.cdt.core.parser.IncludeFileContentProvider; +import org.eclipse.cdt.internal.core.parser.IMacroDictionary; import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContent; import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContent.InclusionKind; import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContentProvider; @@ -37,8 +42,7 @@ import org.eclipse.cdt.internal.core.pdom.AbstractIndexerTask.IndexFileContent; import org.eclipse.core.runtime.CoreException; /** - * Code reader factory, that fakes code readers for header files already stored in the - * index. + * Code reader factory, that fakes code readers for header files already stored in the index. */ public final class IndexBasedFileContentProvider extends InternalFileContentProvider { private static final class NeedToParseException extends Exception {} @@ -46,14 +50,15 @@ public final class IndexBasedFileContentProvider extends InternalFileContentProv private final IIndex fIndex; private int fLinkage; - private Set fIncludedFiles= new HashSet(); /** The fall-back code reader factory used in case a header file is not indexed */ private final InternalFileContentProvider fFallBackFactory; private final ASTFilePathResolver fPathResolver; private final AbstractIndexerTask fRelatedIndexerTask; - private boolean fSupportFillGapFromContextToHeader= false; + private boolean fSupportFillGapFromContextToHeader; private long fFileSizeLimit= 0; - + + private final Map fPragmaOnce= new HashMap(); + public IndexBasedFileContentProvider(IIndex index, ASTFilePathResolver pathResolver, int linkage, IncludeFileContentProvider fallbackFactory) { this(index, pathResolver, linkage, fallbackFactory, null); @@ -79,63 +84,65 @@ public final class IndexBasedFileContentProvider extends InternalFileContentProv public void setLinkage(int linkageID) { fLinkage= linkageID; } - - public void cleanupAfterTranslationUnit() { - fIncludedFiles.clear(); - } + @Override + public void resetPragmaOnceTracking() { + fPragmaOnce.clear(); + } + + /** + * Reports detection of pragma once semantics. + */ + @Override + public void reportPragmaOnceSemantics(String filePath, IFileNomination nom) { + fPragmaOnce.put(fPathResolver.resolveIncludeFile(filePath), nom); + } + + /** + * Returns whether the given file has been included with pragma once semantics. + */ + @Override + public IFileNomination isIncludedWithPragmaOnceSemantics(String filePath) { + return fPragmaOnce.get(fPathResolver.resolveIncludeFile(filePath)); + } + @Override public boolean getInclusionExists(String path) { return fPathResolver.doesIncludeFileExist(path); } - @Override - public void reportTranslationUnitFile(String path) { - IIndexFileLocation ifl= fPathResolver.resolveASTPath(path); - fIncludedFiles.add(ifl); - } - - @Override - public Boolean hasFileBeenIncludedInCurrentTranslationUnit(String path) { - IIndexFileLocation ifl= fPathResolver.resolveASTPath(path); - return fIncludedFiles.contains(ifl); - } @Override - public InternalFileContent getContentForInclusion(String path) { + public InternalFileContent getContentForInclusion(String path, IMacroDictionary macroDictionary) { IIndexFileLocation ifl= fPathResolver.resolveIncludeFile(path); if (ifl == null) { return null; } + path= fPathResolver.getASTPath(ifl); - - // Include files once, only. - if (!fIncludedFiles.add(ifl)) { - return new InternalFileContent(path, InclusionKind.SKIP_FILE); - } - try { - IIndexFile file= fIndex.getFile(fLinkage, ifl); + IIndexFile file = selectIndexFile(macroDictionary, ifl); if (file != null) { try { List files= new ArrayList(); List macros= new ArrayList(); List directives= new ArrayList(); - Set ifls= new HashSet(); - collectFileContent(file, ifls, files, macros, directives, false); - // add included files only, if no exception was thrown - fIncludedFiles.addAll(ifls); - return new InternalFileContent(path, macros, directives, files); + Map newPragmaOnce= new HashMap(); + collectFileContent(file, null, newPragmaOnce, files, macros, directives, null); + // Report pragma once inclusions, only if no exception was thrown. + fPragmaOnce.putAll(newPragmaOnce); + List newPragmaOncePaths = toPathList(newPragmaOnce.keySet()); + return new InternalFileContent(path, macros, directives, files, newPragmaOncePaths); } catch (NeedToParseException e) { } - } + } } catch (CoreException e) { CCorePlugin.log(e); } - + // Skip large files if (fFileSizeLimit > 0 && fPathResolver.getFileSize(path) > fFileSizeLimit) { - return new InternalFileContent(path, InclusionKind.SKIP_FILE); + return new InternalFileContent(path, InclusionKind.SKIP_FILE, null); } if (fFallBackFactory != null) { @@ -147,6 +154,26 @@ public final class IndexBasedFileContentProvider extends InternalFileContentProv return null; } + public List toPathList(Collection newPragmaOnce) { + List newPragmaOncePaths= new ArrayList(newPragmaOnce.size()); + for (IIndexFileLocation l : newPragmaOnce) { + newPragmaOncePaths.add(fPathResolver.getASTPath(l)); + } + return newPragmaOncePaths; + } + + public IIndexFile selectIndexFile(IMacroDictionary macroDictionary, IIndexFileLocation ifl) + throws CoreException { + if (fRelatedIndexerTask != null) + return fRelatedIndexerTask.selectIndexFile(fLinkage, ifl, macroDictionary); + + for (IIndexFile file : fIndex.getFiles(fLinkage, ifl)) { + if (macroDictionary.satisfies(file.getSignificantMacros())) + return file; + } + return null; + } + @Override public InternalFileContent getContentForInclusion(IIndexFileLocation ifl, String astPath) { if (fFallBackFactory != null) { @@ -155,42 +182,71 @@ public final class IndexBasedFileContentProvider extends InternalFileContentProv return null; } - private void collectFileContent(IIndexFile file, Set ifls, List files, - List macros, List usingDirectives, boolean checkIncluded) + private boolean collectFileContent(IIndexFile file, IIndexFile stopAt, Map newPragmaOnce, + List files, List macros, + List usingDirectives, Set preventRecursion) throws CoreException, NeedToParseException { + if (file.equals(stopAt)) + return true; + IIndexFileLocation ifl= file.getLocation(); - if (!ifls.add(ifl) || (checkIncluded && fIncludedFiles.contains(ifl))) { - return; - } - IndexFileContent content; - if (fRelatedIndexerTask != null) { - content= fRelatedIndexerTask.getFileContent(fLinkage, ifl); - if (content == null) { - throw new NeedToParseException(); - } + if (newPragmaOnce.containsKey(ifl)) + return false; + if (file.hasPragmaOnceSemantics()) + newPragmaOnce.put(ifl, file); + + if (preventRecursion != null) { + if (fPragmaOnce.containsKey(ifl)) + return false; } else { - content= new IndexFileContent(); - content.setPreprocessorDirectives(file.getIncludes(), file.getMacros()); - content.setUsingDirectives(file.getUsingDirectives()); + preventRecursion= new HashSet(); + } + if (!preventRecursion.add(file)) + return false; + + final ICPPUsingDirective[] uds; + final Object[] pds; + if (fRelatedIndexerTask != null) { + IndexFileContent content= fRelatedIndexerTask.getFileContent(fLinkage, ifl, file); + if (content == null) + throw new NeedToParseException(); + uds= content.getUsingDirectives(); + pds= content.getPreprocessingDirectives(); + } else { + uds= file.getUsingDirectives(); + pds= IndexFileContent.merge(file.getIncludes(), file.getMacros()); } files.add(file); - usingDirectives.addAll(Arrays.asList(content.getUsingDirectives())); - Object[] dirs= content.getPreprocessingDirectives(); - for (Object d : dirs) { + int udx= 0; + for (Object d : pds) { if (d instanceof IIndexMacro) { macros.add((IIndexMacro) d); } else if (d instanceof IIndexInclude) { + IIndexInclude inc= (IIndexInclude) d; IIndexFile includedFile= fIndex.resolveInclude((IIndexInclude) d); if (includedFile != null) { - collectFileContent(includedFile, ifls, files, macros, usingDirectives, true); + // Add in using directives that appear before the inclusion + final int offset= inc.getNameOffset(); + for (; udx < uds.length && uds[udx].getPointOfDeclaration() <= offset; udx++) { + usingDirectives.add(uds[udx]); + } + if (collectFileContent(includedFile, stopAt, newPragmaOnce, files, macros, usingDirectives, preventRecursion)) + return true; } } } + // Add in remaining using directives + for (; udx < uds.length; udx++) { + usingDirectives.add(uds[udx]); + } + preventRecursion.remove(file); + return false; } @Override - public InternalFileContent getContentForContextToHeaderGap(String path) { + public InternalFileContent getContentForContextToHeaderGap(String path, + IMacroDictionary macroDictionary) { if (!fSupportFillGapFromContextToHeader) { return null; } @@ -199,30 +255,39 @@ public final class IndexBasedFileContentProvider extends InternalFileContentProv if (ifl == null) { return null; } - + try { - IIndexFile targetFile= fIndex.getFile(fLinkage, ifl); + // TODO(197989) This is wrong, the dictionary at this point does not relate to the target + // file. We'll have to provide the target file from the outside (i.e. from the indexer + // task. + IIndexFile targetFile = selectIndexFile(macroDictionary, ifl); if (targetFile == null) { return null; } - + IIndexFile contextFile= findContext(targetFile); if (contextFile == targetFile || contextFile == null) { return null; } - HashSet filesIncluded= new HashSet(); + Map newPragmaOnce= new HashMap(); + List filesIncluded= new ArrayList(); ArrayList macros= new ArrayList(); ArrayList directives= new ArrayList(); - if (!collectFileContentForGap(contextFile, ifl, filesIncluded, macros, directives)) { + try { + if (!collectFileContent(contextFile, targetFile, newPragmaOnce, + filesIncluded, macros, directives, new HashSet())) { + return null; + } + } catch (NeedToParseException e) { return null; } - // mark the files in the gap as included - for (IIndexFile file : filesIncluded) { - fIncludedFiles.add(file.getLocation()); - } - return new InternalFileContent(GAP, macros, directives, new ArrayList(filesIncluded)); + // Report pragma once inclusions. + fPragmaOnce.putAll(newPragmaOnce); + List newPragmaOncePaths = toPathList(newPragmaOnce.keySet()); + return new InternalFileContent(GAP, macros, directives, new ArrayList(filesIncluded), + newPragmaOncePaths); } catch (CoreException e) { CCorePlugin.log(e); } @@ -244,56 +309,12 @@ public final class IndexBasedFileContentProvider extends InternalFileContentProv return file; } - private boolean collectFileContentForGap(IIndexFile from, IIndexFileLocation to, - Set filesIncluded, List macros, - List directives) throws CoreException { - final IIndexFileLocation ifl= from.getLocation(); - if (ifl.equals(to)) { - return true; - } - if (fIncludedFiles.contains(ifl) || !filesIncluded.add(from)) { - return false; - } - - final IIndexInclude[] ids= from.getIncludes(); - final IIndexMacro[] ms= from.getMacros(); - final Object[] dirs= IndexFileContent.merge(ids, ms); - IIndexInclude success= null; - for (Object d : dirs) { - if (d instanceof IIndexMacro) { - macros.add((IIndexMacro) d); - } else if (d instanceof IIndexInclude) { - IIndexFile includedFile= fIndex.resolveInclude((IIndexInclude) d); - if (includedFile != null) { - if (collectFileContentForGap(includedFile, to, filesIncluded, macros, directives)) { - success= (IIndexInclude) d; - break; - } - } - } - } - - final ICPPUsingDirective[] uds= from.getUsingDirectives(); - if (success == null) { - directives.addAll(Arrays.asList(uds)); - return false; - } - - final int offset= success.getNameOffset(); - for (ICPPUsingDirective ud : uds) { - if (ud.getPointOfDeclaration() > offset) - break; - directives.add(ud); - } - return true; - } - - public IIndexFile findIndexFile(InternalFileContent fc) throws CoreException { + public IIndexFile[] findIndexFiles(InternalFileContent fc) throws CoreException { IIndexFileLocation ifl = fPathResolver.resolveASTPath(fc.getFileLocation()); if (ifl != null) { - return fIndex.getFile(fLinkage, ifl); + return fIndex.getFiles(fLinkage, ifl); } - return null; + return IIndexFile.EMPTY_FILE_ARRAY; } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IndexFileSet.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IndexFileSet.java index d244250377d..395eefc0664 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IndexFileSet.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IndexFileSet.java @@ -40,6 +40,15 @@ public class IndexFileSet implements IIndexFileSet { subSet.add(fragFile); } + public void remove(IIndexFile indexFile) { + final IIndexFragmentFile fragFile = (IIndexFragmentFile) indexFile; + final IIndexFragment frag= fragFile.getIndexFragment(); + IIndexFragmentFileSet subSet= fSubSets.get(frag); + if (subSet != null) { + subSet.remove(fragFile); + } + } + public boolean containsDeclaration(IIndexBinding binding) { return containsDeclaration(binding, false); } @@ -163,6 +172,10 @@ public class IndexFileSet implements IIndexFileSet { public void add(IIndexFile indexFile) { Assert.isLegal(false); } + + public void remove(IIndexFile indexFile) { + Assert.isLegal(false); + } }; } return fInverse; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/WritableCIndex.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/WritableCIndex.java index 8bd8489a716..ce596e117af 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/WritableCIndex.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/WritableCIndex.java @@ -18,6 +18,7 @@ import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement; import org.eclipse.cdt.core.index.IIndexFile; import org.eclipse.cdt.core.index.IIndexFileLocation; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.internal.core.pdom.ASTFilePathResolver; import org.eclipse.cdt.internal.core.pdom.YieldableIndexLock; import org.eclipse.core.runtime.CoreException; @@ -43,20 +44,23 @@ public class WritableCIndex extends CIndex implements IWritableIndex { return fWritableFragment; } - public IIndexFragmentFile getWritableFile(int linkageID, IIndexFileLocation location) throws CoreException { - return fWritableFragment.getFile(linkageID, location); + public IIndexFragmentFile getWritableFile(int linkageID, IIndexFileLocation location, + ISignificantMacros macroDictionary) throws CoreException { + return fWritableFragment.getFile(linkageID, location, macroDictionary); } public IIndexFragmentFile[] getWritableFiles(IIndexFileLocation location) throws CoreException { return fWritableFragment.getFiles(location); } - public IIndexFragmentFile addFile(int linkageID, IIndexFileLocation location) throws CoreException { - return fWritableFragment.addFile(linkageID, location); + public IIndexFragmentFile addFile(int linkageID, IIndexFileLocation location, + ISignificantMacros macroDictionary) throws CoreException { + return fWritableFragment.addFile(linkageID, location, macroDictionary); } - public IIndexFragmentFile addUncommittedFile(int linkageID, IIndexFileLocation location) throws CoreException { - return fWritableFragment.addUncommittedFile(linkageID, location); + public IIndexFragmentFile addUncommittedFile(int linkageID, IIndexFileLocation location, + ISignificantMacros macroDictionary) throws CoreException { + return fWritableFragment.addUncommittedFile(linkageID, location, macroDictionary); } public IIndexFragmentFile commitUncommittedFile() throws CoreException { @@ -78,9 +82,10 @@ public class WritableCIndex extends CIndex implements IWritableIndex { if (!isWritableFragment(indexFragment)) { assert false : "Attempt to update file of read-only fragment"; //$NON-NLS-1$ } else { - for (IncludeInformation ii : includes) { - if (ii.fLocation != null) { - ii.fTargetFile= addFile(linkageID, ii.fLocation); + for (IncludeInformation include : includes) { + if (include.fLocation != null) { + include.fTargetFile= addFile(linkageID, include.fLocation, + include.fStatement.getSignificantMacros()); } } ((IWritableIndexFragment) indexFragment).addFileContent(file, includes, macros, names, resolver, lock); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/CodeReaderFactoryAdapter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/CodeReaderFactoryAdapter.java index 39571347044..3ac9468aaab 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/CodeReaderFactoryAdapter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/CodeReaderFactoryAdapter.java @@ -45,7 +45,7 @@ public class CodeReaderFactoryAdapter extends AbstractCodeReaderFactory { } public org.eclipse.cdt.core.parser.CodeReader createCodeReaderForInclusion(String path) { - return CodeReaderAdapter.adapt(fDelegate.getContentForInclusion(path)); + return CodeReaderAdapter.adapt(fDelegate.getContentForInclusion(path, null)); } @Override @@ -55,7 +55,7 @@ public class CodeReaderFactoryAdapter extends AbstractCodeReaderFactory { } public org.eclipse.cdt.core.parser.CodeReader createCodeReaderForTranslationUnit(String path) { - return CodeReaderAdapter.adapt(fDelegate.getContentForInclusion(path)); + return CodeReaderAdapter.adapt(fDelegate.getContentForInclusion(path, null)); } @Deprecated diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/EmptyFilesProvider.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/EmptyFilesProvider.java index f016fcb7982..163488ec3e3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/EmptyFilesProvider.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/EmptyFilesProvider.java @@ -27,7 +27,8 @@ public class EmptyFilesProvider extends InternalFileContentProvider { } @Override - public InternalFileContent getContentForInclusion(String path) { + public InternalFileContent getContentForInclusion(String path, + IMacroDictionary macroDictionary) { if (!getInclusionExists(path)) return null; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/FileContentProviderAdapter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/FileContentProviderAdapter.java index 33d65e001f9..08406327aab 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/FileContentProviderAdapter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/FileContentProviderAdapter.java @@ -6,7 +6,7 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Markus Schorn - initial API and implementation + * Markus Schorn - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.internal.core.parser; @@ -26,7 +26,7 @@ import org.eclipse.core.runtime.CoreException; public class FileContentProviderAdapter extends InternalFileContentProvider { /** - * @deprecated avoid using the adapter, its for backwards compatibility, only. + * @deprecated avoid using the adapter, it's for backwards compatibility, only. */ @Deprecated public static InternalFileContentProvider adapt(ICodeReaderFactory fileCreator) { @@ -57,7 +57,7 @@ public class FileContentProviderAdapter extends InternalFileContentProvider { } @Override - public InternalFileContent getContentForInclusion(String path) { + public InternalFileContent getContentForInclusion(String path, IMacroDictionary macroDictionary) { return (InternalFileContent) FileContent.adapt(fDelegate.createCodeReaderForInclusion(path)); } @@ -72,5 +72,4 @@ public class FileContentProviderAdapter extends InternalFileContentProvider { } return null; } - } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/IMacroDictionary.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/IMacroDictionary.java new file mode 100644 index 00000000000..a6f854960a2 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/IMacroDictionary.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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 + * + * Contributors: + * Markus Schorn - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.core.parser; + +import org.eclipse.cdt.core.parser.ISignificantMacros; + + +/** + * Interface for accessing the macro dictionary of the preprocessor. + */ +public interface IMacroDictionary { + + boolean satisfies(ISignificantMacros significantMacros); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/SavedFilesProvider.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/SavedFilesProvider.java index 5dff2328055..0cea421a535 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/SavedFilesProvider.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/SavedFilesProvider.java @@ -30,7 +30,8 @@ public class SavedFilesProvider extends InternalFileContentProvider { } @Override - public InternalFileContent getContentForInclusion(String path) { + public InternalFileContent getContentForInclusion(String path, + IMacroDictionary macroDictionary) { if (!getInclusionExists(path)) return null; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java index 23ca3939424..f5e6b0812d4 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java @@ -6,7 +6,7 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Markus Schorn - initial API and implementation + * Markus Schorn - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.internal.core.parser.scanner; @@ -40,11 +40,14 @@ import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit.IDependencyTree; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit.IDependencyTree.IASTInclusionNode; import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.IFileNomination; import org.eclipse.cdt.core.dom.ast.IMacroBinding; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.core.parser.IToken; import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.ASTNodeSpecification; +import org.eclipse.core.runtime.CoreException; /** * Models various AST-constructs obtained from the preprocessor. @@ -188,7 +191,7 @@ class ASTIfndef extends ASTDirectiveWithCondition implements IASTPreprocessorIfn } class ASTIfdef extends ASTDirectiveWithCondition implements IASTPreprocessorIfdefStatement { - ASTMacroReferenceName fMacroRef; + private ASTMacroReferenceName fMacroRef; public ASTIfdef(IASTTranslationUnit parent, int startNumber, int condNumber, int condEndNumber, boolean taken, IMacroBinding macro) { super(parent, startNumber, condNumber, condEndNumber, taken); if (macro != null) { @@ -258,16 +261,24 @@ class ASTInclusionStatement extends ASTPreprocessorNode implements IASTPreproces private final boolean fIsResolved; private final boolean fIsSystemInclude; private final boolean fFoundByHeuristics; + private final IFileNomination fNominationDelegate; + private boolean fPragmaOnce; + private boolean fComplete; + private ISignificantMacros fSignificantMacros; public ASTInclusionStatement(IASTTranslationUnit parent, int startNumber, int nameStartNumber, int nameEndNumber, int endNumber, - char[] headerName, String filePath, boolean userInclude, boolean active, boolean heuristic) { + char[] headerName, String filePath, boolean userInclude, boolean active, boolean heuristic, + IFileNomination nominationDelegate) { super(parent, IASTTranslationUnit.PREPROCESSOR_STATEMENT, startNumber, endNumber); - fName= new ASTPreprocessorName(this, IASTPreprocessorIncludeStatement.INCLUDE_NAME, nameStartNumber, nameEndNumber, headerName, null); + fName= new ASTPreprocessorName(this, IASTPreprocessorIncludeStatement.INCLUDE_NAME, + nameStartNumber, nameEndNumber, headerName, null); fPath= filePath == null ? "" : filePath; //$NON-NLS-1$ fIsResolved= filePath != null; fIsSystemInclude= !userInclude; fFoundByHeuristics= heuristic; + fSignificantMacros= ISignificantMacros.NONE; + fNominationDelegate= nominationDelegate; if (!active) { setInactive(); } @@ -298,6 +309,42 @@ class ASTInclusionStatement extends ASTPreprocessorNode implements IASTPreproces public boolean isResolvedByHeuristics() { return fFoundByHeuristics; } + + public boolean hasPragmaOnceSemantics() { + if (fNominationDelegate != null) { + try { + return fNominationDelegate.hasPragmaOnceSemantics(); + } catch (CoreException e) { + } + } + return fPragmaOnce; + } + + public void setPragamOnceSemantics(boolean value) { + assert fNominationDelegate == null; + fPragmaOnce= value; + } + + public ISignificantMacros getSignificantMacros() { + if (fNominationDelegate != null) { + try { + return fNominationDelegate.getSignificantMacros(); + } catch (CoreException e) { + } + } + return fSignificantMacros; + } + + public void setSignificantMacros(ISignificantMacros sig) { + assert sig != null; + assert fNominationDelegate == null; + fSignificantMacros= sig; + fComplete= true; + } + + public boolean isComplete() { + return fComplete; + } } class ASTMacroDefinition extends ASTPreprocessorNode implements IASTPreprocessorObjectStyleMacroDefinition { @@ -579,6 +626,10 @@ class ASTFileLocation implements IASTFileLocation { public LocationCtxFile getLocationContext() { return fLocationCtx; } + + public IASTPreprocessorIncludeStatement getContextInclusionStatement() { + return fLocationCtx.getInclusionStatement(); + } } class ASTMacroExpansion extends ASTPreprocessorNode implements IASTPreprocessorMacroExpansion { @@ -708,6 +759,10 @@ class ASTFileLocationForBuiltins implements IASTFileLocation { public int getStartingLineNumber() { return 0; } + + public IASTPreprocessorIncludeStatement getContextInclusionStatement() { + return null; + } } @@ -723,4 +778,3 @@ class ASTImageLocation extends ASTFileLocationForBuiltins implements IASTImageLo return fKind; } } - diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java index a832728cba2..1839974653c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2010 IBM Corporation and others. + * Copyright (c) 2004, 2011 IBM Corporation 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 @@ -19,12 +19,17 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.IFileNomination; import org.eclipse.cdt.core.dom.ast.IMacroBinding; import org.eclipse.cdt.core.dom.parser.IScannerExtensionConfiguration; import org.eclipse.cdt.core.index.IIndexMacro; +import org.eclipse.cdt.core.parser.AbstractParserLogService; import org.eclipse.cdt.core.parser.EndOfFileException; import org.eclipse.cdt.core.parser.FileContent; import org.eclipse.cdt.core.parser.IExtendedScannerInfo; @@ -34,6 +39,7 @@ import org.eclipse.cdt.core.parser.IPreprocessorDirective; import org.eclipse.cdt.core.parser.IProblem; import org.eclipse.cdt.core.parser.IScanner; import org.eclipse.cdt.core.parser.IScannerInfo; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.core.parser.IToken; import org.eclipse.cdt.core.parser.IncludeFileContentProvider; import org.eclipse.cdt.core.parser.Keywords; @@ -45,6 +51,7 @@ import org.eclipse.cdt.core.parser.util.CharArrayMap; import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.internal.core.dom.IIncludeFileResolutionHeuristics; import org.eclipse.cdt.internal.core.parser.EmptyFilesProvider; +import org.eclipse.cdt.internal.core.parser.IMacroDictionary; import org.eclipse.cdt.internal.core.parser.scanner.ExpressionEvaluator.EvalException; import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContent.InclusionKind; import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions; @@ -52,6 +59,7 @@ import org.eclipse.cdt.internal.core.parser.scanner.MacroDefinitionParser.Invali import org.eclipse.cdt.internal.core.parser.scanner.ScannerContext.BranchKind; import org.eclipse.cdt.internal.core.parser.scanner.ScannerContext.CodeState; import org.eclipse.cdt.internal.core.parser.scanner.ScannerContext.Conditional; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; /** @@ -88,11 +96,45 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { private static final DynamicMacro __DATE__= new DateMacro("__DATE__".toCharArray()); //$NON-NLS-1$ private static final DynamicMacro __TIME__ = new TimeMacro("__TIME__".toCharArray()); //$NON-NLS-1$ private static final DynamicMacro __LINE__ = new LineMacro("__LINE__".toCharArray()); //$NON-NLS-1$ + private static final char[] ONCE = "once".toCharArray(); //$NON-NLS-1$ private static final int NO_EXPANSION = 0x01; private static final int PROTECT_DEFINED = 0x02; private static final int STOP_AT_NL = 0x04; private static final int CHECK_NUMBERS = 0x08; + private static final int REPORT_SIGNIFICANT_MACROS = 0x10; + + private static final int MAX_INCLUSION_DEPTH = 200; + + private static final String TRACE_NO_GUARD = CCorePlugin.PLUGIN_ID + "/debug/scanner/missingIncludeGuards"; //$NON-NLS-1$ + + + private final class MacroDictionary implements IMacroDictionary, ISignificantMacros.IVisitor { + public boolean satisfies(ISignificantMacros significantMacros) { + return significantMacros.accept(this); + } + + public boolean visitDefined(char[] macro) { + return isDefined(macro); + } + + public boolean visitUndefined(char[] macro) { + return !isDefined(macro); + } + + public boolean visitValue(char[] macro, char[] value) { + PreprocessorMacro m = fMacroDictionary.get(macro); + return m != null && CharArrayUtils.equals(m.getExpansion(), value); + } + + private boolean isDefined(char[] macro) { + return fMacroDictionary.containsKey(macro); + } + + public boolean visitIncluded(char[] path) { + return fFileContentProvider.isIncludedWithPragmaOnceSemantics(new String(path)) != null; + } + } private interface IIncludeFileTester { T checkFile(String path, boolean isHeuristicMatch, IncludeSearchPathElement onPath); @@ -100,7 +142,13 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { final private IIncludeFileTester createCodeReaderTester= new IIncludeFileTester() { public InternalFileContent checkFile(String path, boolean isHeuristicMatch, IncludeSearchPathElement onPath) { - final InternalFileContent fc= fFileContentProvider.getContentForInclusion(path); + final InternalFileContent fc; + IFileNomination once= fFileContentProvider.isIncludedWithPragmaOnceSemantics(path); + if (once != null) { + fc= new InternalFileContent(path, InclusionKind.SKIP_FILE, once); + } else { + fc= fFileContentProvider.getContentForInclusion(path, fMacroDictionaryFacade); + } if (fc != null) { fc.setFoundByHeuristics(isHeuristicMatch); fc.setFoundOnPath(onPath); @@ -162,7 +210,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { TokenSequence fInputToMacroExpansion= new TokenSequence(false); TokenSequence fLineInputToMacroExpansion= new TokenSequence(true); - final private IParserLogService fLog; + final private AbstractParserLogService fLog; final private InternalFileContentProvider fFileContentProvider; private IIncludeFileResolutionHeuristics fIncludeFileResolutionHeuristics; @@ -184,11 +232,9 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { // state information private final CharArrayMap fMacroDictionary = new CharArrayMap(512); + private final IMacroDictionary fMacroDictionaryFacade = new MacroDictionary(); private final LocationMap fLocationMap; - /** Set of already included files */ - private final HashSet fAllIncludedFiles= new HashSet(); - private final Lexer fRootLexer; private final ScannerContext fRootContext; protected ScannerContext fCurrentContext; @@ -200,6 +246,12 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { private Token fLastToken; private InternalFileContent fRootContent; + private boolean fHandledEndOfTranslationUnit; + + // Detection of include guards used around an include directive + private char[] fExternIncludeGuard; + private Set fTracedGuards; + public CPreprocessor(FileContent fileContent, IScannerInfo info, ParserLanguage language, IParserLogService log, IScannerExtensionConfiguration configuration, @@ -217,7 +269,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { throw new IllegalArgumentException("Illegal file content object"); //$NON-NLS-1$ } - fLog = log; + fLog = AbstractParserLogService.convert(log); fAdditionalNumericLiteralSuffixes= nonNull(configuration.supportAdditionalNumericLiteralSuffixes()); fLexOptions.fSupportDollarInIdentifiers= configuration.support$InIdentifiers(); fLexOptions.fSupportAtSignInIdentifiers= configuration.supportAtSignInIdentifiers(); @@ -239,17 +291,37 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { setupMacroDictionary(configuration, info, language); ILocationCtx ctx= fLocationMap.pushTranslationUnit(filePath, fRootContent.getSource()); - fAllIncludedFiles.add(filePath); - fFileContentProvider.reportTranslationUnitFile(filePath); fRootLexer= new Lexer(fRootContent.getSource(), fLexOptions, this, this); - fRootContext= fCurrentContext= new ScannerContext(ctx, null, fRootLexer); + fRootContext= fCurrentContext= new ScannerContext(ctx, null, fRootLexer, true); if (info instanceof IExtendedScannerInfo) { final IExtendedScannerInfo einfo= (IExtendedScannerInfo) info; - fPreIncludedFiles= new String[][] {einfo.getMacroFiles(), einfo.getIncludeFiles()}; + fPreIncludedFiles= new String[][] { einfo.getMacroFiles(), einfo.getIncludeFiles() }; } + fFileContentProvider.resetPragmaOnceTracking(); + detectIncludeGuard(filePath, fRootContent.getSource(), fRootContext); } + + private char[] detectIncludeGuard(String filePath, AbstractCharArray source, ScannerContext ctx) { + final char[] guard = IncludeGuardDetection.detectIncludeGuard(source, fLexOptions, fPPKeywords); + if (guard != null) { + IFileNomination nom= fLocationMap.reportPragmaOnceSemantics(ctx.getLocationCtx()); + fFileContentProvider.reportPragmaOnceSemantics(filePath, nom); + ctx.internalModification(guard); + ctx.internalModification(filePath.toCharArray()); + return guard; + } + if (ctx != fRootContext) { + if (fLog.isTracing(TRACE_NO_GUARD)) { + if (fTracedGuards == null) + fTracedGuards= new HashSet(); + if (fTracedGuards.add(filePath)) + fLog.traceLog(TRACE_NO_GUARD, "No include guard in " + filePath); //$NON-NLS-1$ + } + } + return null; + } - public void setSplitShiftROperator(boolean val) { + public void setSplitShiftROperator(boolean val) { fSplitShiftRightOperator= val; } @@ -370,16 +442,17 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { } private void beforeFirstFetchToken() { - if (fPreIncludedFiles != null) { - handlePreIncludedFiles(); - } - final String location = fLocationMap.getTranslationUnitPath(); - InternalFileContent content= fFileContentProvider.getContentForContextToHeaderGap(location); + final String location = fLocationMap.getTranslationUnitPath(); + InternalFileContent content= fFileContentProvider.getContentForContextToHeaderGap(location, + fMacroDictionaryFacade); if (content != null && content.getKind() == InclusionKind.FOUND_IN_INDEX) { processInclusionFromIndex(0, location, content); + fPreIncludedFiles= null; + } else if (fPreIncludedFiles != null) { + handlePreIncludedFiles(); } - fLocationMap.replacingFile(fFileContentProvider, fRootContent); - fRootContent= null; + fLocationMap.parsingFile(fFileContentProvider, fRootContent); + fRootContent= null; } private void handlePreIncludedFiles() { @@ -387,14 +460,14 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { if (imacro != null && imacro.length > 0) { final char[] buffer= createSyntheticFile(imacro); ILocationCtx ctx= fLocationMap.pushPreInclusion(new CharArray(buffer), 0, true); - fCurrentContext= new ScannerContext(ctx, fCurrentContext, new Lexer(buffer, fLexOptions, this, this)); + fCurrentContext= new ScannerContext(ctx, fCurrentContext, new Lexer(buffer, fLexOptions, this, this), false); ScannerContext preCtx= fCurrentContext; try { while (internalFetchToken(preCtx, CHECK_NUMBERS, false).getType() != IToken.tEND_OF_INPUT) { // just eat the tokens } final ILocationCtx locationCtx = fCurrentContext.getLocationCtx(); - fLocationMap.popContext(locationCtx); + fLocationMap.popContext(locationCtx, null); fCurrentContext= fCurrentContext.getParent(); assert fCurrentContext == fRootContext; } catch (OffsetLimitReachedException e) { @@ -404,7 +477,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { if (include != null && include.length > 0) { final char[] buffer= createSyntheticFile(include); ILocationCtx ctx= fLocationMap.pushPreInclusion(new CharArray(buffer), 0, false); - fCurrentContext= new ScannerContext(ctx, fCurrentContext, new Lexer(buffer, fLexOptions, this, this)); + fCurrentContext= new ScannerContext(ctx, fCurrentContext, new Lexer(buffer, fLexOptions, this, this), false); } fPreIncludedFiles= null; } @@ -726,11 +799,17 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { case IToken.tEND_OF_INPUT: if (fCurrentContext == uptoEndOfCtx || uptoEndOfCtx == null) { + if (fCurrentContext == fRootContext && !fHandledEndOfTranslationUnit + && (options & STOP_AT_NL) == 0) { + fHandledEndOfTranslationUnit= true; + fLocationMap.endTranslationUnit(ppToken.getEndOffset(), fCurrentContext.getSignificantMacros()); + } return ppToken; } - final ILocationCtx locationCtx = fCurrentContext.getLocationCtx(); - fLocationMap.popContext(locationCtx); - fCurrentContext= fCurrentContext.getParent(); + final ILocationCtx locationCtx = fCurrentContext.getLocationCtx(); + fLocationMap.popContext(locationCtx, fCurrentContext.getSignificantMacros()); + fCurrentContext.propagateSignificantMacros(); + fCurrentContext= fCurrentContext.getParent(); assert fCurrentContext != null; ppToken= fCurrentContext.currentLexerToken(); @@ -781,7 +860,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { } } - private void checkNumber(Token number, final boolean isFloat) { + private void checkNumber(Token number, final boolean isFloat) { final char[] image= number.getCharImage(); boolean hasExponent = false; @@ -1151,7 +1230,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { } break; case IPreprocessorDirective.ppPragma: - condOffset= lexer.nextToken().getOffset(); + Token pragmaToken= lexer.nextToken(); + condOffset= pragmaToken.getOffset(); condEndOffset= lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE); // Missing argument if (condEndOffset < condOffset) { @@ -1160,6 +1240,10 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { if (fCurrentContext.getCodeState() == CodeState.eActive) { int endOffset= lexer.currentToken().getEndOffset(); fLocationMap.encounterPoundPragma(startOffset, condOffset, condEndOffset, endOffset); + if (CharArrayUtils.equals(ONCE, pragmaToken.getCharImage())) { + IFileNomination nom= fLocationMap.reportPragmaOnceSemantics(fCurrentContext.getLocationCtx()); + fFileContentProvider.reportPragmaOnceSemantics(getCurrentFilename(), nom); + } } break; case IPreprocessorDirective.ppIgnore: @@ -1175,16 +1259,12 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { } } - private boolean hasFileBeenIncluded(String location) { - Boolean itHas= fFileContentProvider.hasFileBeenIncludedInCurrentTranslationUnit(location); - if (itHas != null) { - return itHas.booleanValue(); - } - return fAllIncludedFiles.contains(location); - } - private void executeInclude(final Lexer lexer, int poundOffset, boolean include_next, boolean active, boolean withinExpansion) throws OffsetLimitReachedException { + // Make sure to clear the extern include guard. + final char[] externGuard= fExternIncludeGuard; + fExternIncludeGuard= null; + if (withinExpansion) { final char[] name= lexer.currentToken().getCharImage(); final int endOffset = lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE); @@ -1258,19 +1338,36 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { } return; } - + + if (active && fCurrentContext.getDepth() == MAX_INCLUSION_DEPTH) { + handleProblem(IProblem.PREPROCESSOR_EXCEEDS_MAXIMUM_INCLUSION_DEPTH, + lexer.getInputChars(poundOffset, condEndOffset), poundOffset, condEndOffset); + return; + } + String path= null; boolean reported= false; boolean isHeuristic= false; + IFileNomination nominationDelegate= null; final String includeDirective = new String(headerName); if (!active) { - // test if the include is inactive just because it was included before (bug 167100) - final IncludeResolution resolved= findInclusion(includeDirective, userInclude, include_next, - getCurrentFilename(), createPathTester); - if (resolved != null && hasFileBeenIncluded(resolved.fLocation)) { - path= resolved.fLocation; - isHeuristic= resolved.fHeuristic; + // #ifndef GUARD + // #include "file.h" + // #endif + if (externGuard != null) { + // When the extern guard matches we need to resolve the inclusion. We don't actually + // check whether the guard matches. + final IncludeResolution resolved= findInclusion(includeDirective, userInclude, include_next, + getCurrentFilename(), createPathTester); + if (resolved != null) { + nominationDelegate = fFileContentProvider.isIncludedWithPragmaOnceSemantics(resolved.fLocation); + if (nominationDelegate != null) { + path= resolved.fLocation; + isHeuristic= resolved.fHeuristic; + fCurrentContext.undoSignificance(externGuard); + } + } } } else { final InternalFileContent fi= findInclusion(includeDirective, userInclude, include_next, @@ -1280,24 +1377,62 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { isHeuristic= fi.isFoundByHeuristics(); switch (fi.getKind()) { case FOUND_IN_INDEX: + nominationDelegate= fi.getFilesIncluded().get(0); + if (nominationDelegate != null) { + try { + ISignificantMacros sm = nominationDelegate.getSignificantMacros(); + fCurrentContext.addSignificantMacros(sm); + } catch (CoreException e) { + } + } processInclusionFromIndex(poundOffset, path, fi); + // When the extern guard matches, it is not significant. + if (externGuard != null && fFileContentProvider.isIncludedWithPragmaOnceSemantics(path) != null + && fMacroDictionary.containsKey(externGuard)) { + List mdefs = fi.getMacroDefinitions(); + if (!mdefs.isEmpty() && CharArrayUtils.equals(mdefs.get(0).getNameCharArray(), externGuard)) { + fCurrentContext.undoSignificance(externGuard); + } + } break; case USE_SOURCE: AbstractCharArray source= fi.getSource(); - if (source != null && !isCircularInclusion(path)) { + if (source != null) { reported= true; - fAllIncludedFiles.add(path); ILocationCtx ctx= fLocationMap.pushInclusion(poundOffset, nameOffsets[0], nameOffsets[1], condEndOffset, source, path, headerName, userInclude, isHeuristic, fi.isSource()); ScannerContext fctx= new ScannerContext(ctx, fCurrentContext, - new Lexer(source, fLexOptions, this, this)); + new Lexer(source, fLexOptions, this, this), true); fctx.setFoundOnPath(fi.getFoundOnPath(), includeDirective); + char[] guard= detectIncludeGuard(path, source, fctx); + if (guard != null) { + fctx.setPragmaOnce(); + // When the extern guard matches, it is not significant. + if (externGuard != null && CharArrayUtils.equals(externGuard, guard)) { + fCurrentContext.undoSignificance(guard); + } + } fCurrentContext= fctx; } - fLocationMap.replacingFile(fFileContentProvider, fi); + fLocationMap.parsingFile(fFileContentProvider, fi); break; case SKIP_FILE: + nominationDelegate= fi.getPragmaOnceNomination(); + if (nominationDelegate != null) { + ISignificantMacros sm= null; + if (nominationDelegate.isComplete()) { + try { + sm = nominationDelegate.getSignificantMacros(); + } catch (CoreException e) { + } + } + if (sm != null && fMacroDictionaryFacade.satisfies(sm)) { + fCurrentContext.addSignificantMacros(sm); + } else { + fCurrentContext.addSignificantInclusion(path); + } + } break; } } else { @@ -1315,7 +1450,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { if (!reported) { fLocationMap.encounterPoundInclude(poundOffset, nameOffsets[0], nameOffsets[1], - condEndOffset, headerName, path, userInclude, active, isHeuristic); + condEndOffset, headerName, path, userInclude, active, isHeuristic, nominationDelegate); } } @@ -1323,6 +1458,10 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { List mdefs= fi.getMacroDefinitions(); for (IIndexMacro macro : mdefs) { addMacroDefinition(macro); + fCurrentContext.internalModification(macro.getNameCharArray()); + } + for (String pragOncePath : fi.getPragmaOncePaths()) { + fCurrentContext.internalModification(pragOncePath.toCharArray()); } fLocationMap.skippedFile(fLocationMap.getSequenceNumberForOffset(offset), fi); } @@ -1346,24 +1485,15 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { return headerName; } - private boolean isCircularInclusion(String filename) { - ILocationCtx checkContext= fCurrentContext.getLocationCtx(); - while (checkContext != null) { - if (filename.equals(checkContext.getFilePath())) { - return true; - } - checkContext= checkContext.getParent(); - } - return false; - } - - private void executeDefine(final Lexer lexer, int startOffset, boolean isActive) throws OffsetLimitReachedException { try { ObjectStyleMacro macrodef = fMacroDefinitionParser.parseMacroDefinition(lexer, this); - if (isActive) - fMacroDictionary.put(macrodef.getNameCharArray(), macrodef); + if (isActive) { + final char[] macroName = macrodef.getNameCharArray(); + fMacroDictionary.put(macroName, macrodef); + fCurrentContext.internalModification(macroName); + } final Token name= fMacroDefinitionParser.getNameToken(); fLocationMap.encounterPoundDefine(startOffset, name.getOffset(), name.getEndOffset(), @@ -1393,6 +1523,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { PreprocessorMacro definition; if (isActive) { definition= fMacroDictionary.remove(namechars, 0, namechars.length); + fCurrentContext.internalModification(namechars); } else { definition= fMacroDictionary.get(namechars); } @@ -1422,10 +1553,19 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { handleProblem(IProblem.PREPROCESSOR_DEFINITION_NOT_FOUND, name.getCharImage(), offset, nameEndOffset); } else { final char[] namechars= name.getCharImage(); + if (isIfndef && !fCurrentContext.hasInternalModification(namechars) + && !fCurrentContext.isSignificant(namechars)) { + if (IncludeGuardDetection.detectIncludeEndif(lexer)) { + fExternIncludeGuard= namechars; + } + } macro= fMacroDictionary.get(namechars); isTaken= (macro == null) == isIfndef; if (macro == null) { macro = new UndefinedMacro(namechars); + fCurrentContext.significantMacroUndefined(namechars); + } else { + fCurrentContext.significantMacroDefined(namechars); } } } @@ -1442,7 +1582,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { return fCurrentContext.setBranchState(conditional, isTaken, withinExpansion, offset); } - private CodeState executeIf(Lexer lexer, int startOffset, boolean isElif, + private CodeState executeIf(Lexer lexer, int startOffset, boolean isElif, boolean withinExpansion) throws OffsetLimitReachedException { Conditional cond= fCurrentContext.newBranch(isElif ? BranchKind.eElif : BranchKind.eIf, withinExpansion); if (cond == null) { @@ -1458,6 +1598,12 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { int condEndOffset, endOffset; if (cond.canHaveActiveBranch(withinExpansion)) { + char[] macro= IncludeGuardDetection.detectIfNotDefinedIncludeEndif(lexer); + if (macro != null && !fCurrentContext.hasInternalModification(macro) + && !fCurrentContext.isSignificant(macro)) { + fExternIncludeGuard= macro; + } + TokenList condition= new TokenList(); condEndOffset= getTokensWithinPPDirective(true, condition, withinExpansion); endOffset= lexer.currentToken().getEndOffset(); @@ -1469,6 +1615,14 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { fExpressionEvaluator.clearMacrosInDefinedExpression(); isTaken= fExpressionEvaluator.evaluate(condition, fMacroDictionary, fLocationMap); refs = fExpressionEvaluator.clearMacrosInDefinedExpression(); + for (IASTName iastName : refs) { + IBinding mb= iastName.getBinding(); + if (mb instanceof UndefinedMacro) { + fCurrentContext.significantMacroUndefined(iastName.toCharArray()); + } else { + fCurrentContext.significantMacroDefined(iastName.toCharArray()); + } + } } catch (EvalException e) { handleProblem(e.getProblemID(), e.getProblemArg(), condOffset, endOffset); } @@ -1531,7 +1685,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { boolean withinExpansion) throws OffsetLimitReachedException { final ScannerContext scannerCtx= fCurrentContext; scannerCtx.clearInactiveCodeMarkerToken(); - int options= STOP_AT_NL; + int options= STOP_AT_NL | REPORT_SIGNIFICANT_MACROS; if (isCondition) options |= PROTECT_DEFINED; @@ -1545,10 +1699,9 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { case Lexer.tNEWLINE: break loop; case IToken.tIDENTIFIER: - if (isCondition && CharArrayUtils.equals(Keywords.cDEFINED, t.getCharImage())) { - t.setType(CPreprocessor.tDEFINED); - options |= NO_EXPANSION; - } + break; + case tDEFINED: + options |= NO_EXPANSION; break; case IToken.tLPAREN: break; @@ -1639,9 +1792,16 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { */ private boolean expandMacro(final Token identifier, Lexer lexer, int options, boolean withinExpansion) throws OffsetLimitReachedException { + final boolean reportSignificant = (options & REPORT_SIGNIFICANT_MACROS) != 0; final char[] name= identifier.getCharImage(); + if ((options & PROTECT_DEFINED) != 0 && CharArrayUtils.equals(name, Keywords.cDEFINED)) { + identifier.setType(tDEFINED); + return false; + } PreprocessorMacro macro= fMacroDictionary.get(name); if (macro == null) { + if (reportSignificant) + fCurrentContext.significantMacroUndefined(name); return false; } boolean stopAtNewline= (options & STOP_AT_NL) != 0; @@ -1653,6 +1813,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { } } if (t.getType() != IToken.tLPAREN) { + if (reportSignificant) + fCurrentContext.significantMacro(macro); return false; } } @@ -1661,7 +1823,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { final MacroExpander expander = withinExpansion ? new MacroExpander(this, fMacroDictionary, fLocationMap, fLexOptions) : fMacroExpander; TokenList replacement= expander.expand(input, (options & PROTECT_DEFINED) != 0, macro, - identifier, contentAssist); + identifier, contentAssist, + reportSignificant ? fCurrentContext : null); final IASTName[] expansions= expander.clearImplicitExpansions(); final ImageLocationInfo[] ili= expander.clearImageLocationInfos(); final Token last= replacement.last(); @@ -1679,5 +1842,5 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { return fMacroExpander; } return null; - } + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ExpressionEvaluator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ExpressionEvaluator.java index fba757060a2..09ccfce9787 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ExpressionEvaluator.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ExpressionEvaluator.java @@ -299,11 +299,13 @@ public class ExpressionEvaluator { if (LA() != IToken.tIDENTIFIER) { throw new EvalException(IProblem.SCANNER_ILLEGAL_IDENTIFIER, null); } - PreprocessorMacro macro= fDictionary.get(fTokens.getCharImage()); - if (macro != null) { - fMacrosInDefinedExpressions.add(fLocationMap.encounterDefinedExpression(macro, fTokens.getOffset(), fTokens.getEndOffset())); - } + final char[] macroName = fTokens.getCharImage(); + PreprocessorMacro macro= fDictionary.get(macroName); int result= macro != null ? 1 : 0; + if (macro == null) + macro= new UndefinedMacro(macroName); + + fMacrosInDefinedExpressions.add(fLocationMap.encounterDefinedExpression(macro, fTokens.getOffset(), fTokens.getEndOffset())); consume(); if (parenthesis) { if (LA() != IToken.tRPAREN) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ISkippedIndexedFilesListener.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ISkippedIndexedFilesListener.java index 607e1fd784d..6e913d46d4d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ISkippedIndexedFilesListener.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ISkippedIndexedFilesListener.java @@ -28,5 +28,5 @@ public interface ISkippedIndexedFilesListener { /** * Notifies the listeners that a file is being parsed. */ - void replacingFile(InternalFileContentProvider fileContentProvider, InternalFileContent fileContent); + void parsingFile(InternalFileContentProvider fileContentProvider, InternalFileContent fileContent); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/IncludeGuardDetection.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/IncludeGuardDetection.java new file mode 100644 index 00000000000..2674e80e36a --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/IncludeGuardDetection.java @@ -0,0 +1,165 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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 + * + * Contributors: + * Markus Schorn - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.core.parser.scanner; + +import static org.eclipse.cdt.core.parser.OffsetLimitReachedException.ORIGIN_PREPROCESSOR_DIRECTIVE; + +import org.eclipse.cdt.core.parser.IPreprocessorDirective; +import org.eclipse.cdt.core.parser.IToken; +import org.eclipse.cdt.core.parser.Keywords; +import org.eclipse.cdt.core.parser.OffsetLimitReachedException; +import org.eclipse.cdt.core.parser.util.CharArrayIntMap; +import org.eclipse.cdt.core.parser.util.CharArrayUtils; + +/** + * Helper class for detecting include guards + */ +public class IncludeGuardDetection { + public static char[] detectIncludeGuard(AbstractCharArray content, Lexer.LexerOptions lexOptions, CharArrayIntMap ppKeywords) { + Lexer l= new Lexer(content, lexOptions, ILexerLog.NULL, null); + char[] guard= findIncludeGuard(l, ppKeywords); + if (guard != null && currentIfSpansFile(l, ppKeywords)) { + return guard; + } + return null; + } + + private static char[] findIncludeGuard(Lexer l, CharArrayIntMap ppKeywords) { + try { + if (skipAll(l, Lexer.tNEWLINE).getType() == IToken.tPOUND) { + Token t = l.nextToken(); + if (t.getType() == IToken.tIDENTIFIER) { + char[] guard= null; + switch(ppKeywords.get(t.getCharImage())) { + case IPreprocessorDirective.ppIfndef: + // #ifndef GUARD + t= l.nextToken(); + if (t.getType() == IToken.tIDENTIFIER) { + guard= t.getCharImage(); + } + break; + case IPreprocessorDirective.ppIf: + // #if !defined GUARD + // #if ((!((defined (GUARD))))) + guard = findNotDefined(l); + break; + } + if (guard != null) { + // #define GUARD + l.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE); + if (skipAll(l, Lexer.tNEWLINE).getType() == IToken.tPOUND + && checkToken(l.nextToken(), Keywords.cDEFINE) + && checkToken(l.nextToken(), guard)) { + l.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE); + return guard; + } + } + } + } + } catch (OffsetLimitReachedException e) { + } + return null; + } + + private static char[] findNotDefined(Lexer l) throws OffsetLimitReachedException { + Token t; + if (skipAll(l, IToken.tLPAREN).getType() == IToken.tNOT + && checkToken(skipAll(l, IToken.tLPAREN), Keywords.cDEFINED)) { + t= l.nextToken(); // only a single parenthesis is allowed + if (t.getType() == IToken.tLPAREN) + t= l.nextToken(); + if (t.getType() == IToken.tIDENTIFIER) { + char[] guard= t.getCharImage(); + if (skipAll(l, IToken.tRPAREN).getType() == Lexer.tNEWLINE) + return guard; + } + } + return null; + } + + private static boolean checkToken(Token t, char[] image) throws OffsetLimitReachedException { + return CharArrayUtils.equals(t.getCharImage(), image); + } + + private static boolean currentIfSpansFile(Lexer l, CharArrayIntMap ppKeywords) { + // Check if the #ifndef spans the entire file + try { + int nesting= 1; + while (nesting > 0) { + Token t= l.nextDirective(); + if (t.getType() == IToken.tEND_OF_INPUT) + return true; + switch(ppKeywords.get(l.nextToken().getCharImage())) { + case IPreprocessorDirective.ppIf: + case IPreprocessorDirective.ppIfdef: + case IPreprocessorDirective.ppIfndef: + nesting++; + break; + case IPreprocessorDirective.ppEndif: + nesting--; + break; + } + } + l.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE); + return skipAll(l, Lexer.tNEWLINE).getType() == IToken.tEND_OF_INPUT; + } catch (OffsetLimitReachedException e) { + } + return true; + } + + private static Token skipAll(Lexer l, int kind) throws OffsetLimitReachedException { + // Skip empty lines + Token t= l.nextToken(); + while (t.getType() == kind) + t= l.nextToken(); + return t; + } + + + public static boolean detectIncludeEndif(Lexer l) { + l.saveState(); + try { + return findIncludeEndif(l); + } catch (OffsetLimitReachedException e) { + } finally { + l.restoreState(); + } + return false; + } + + private static boolean findIncludeEndif(Lexer l) throws OffsetLimitReachedException { + if (skipAll(l, Lexer.tNEWLINE).getType() != IToken.tPOUND) + return false; + if (!checkToken(l.nextToken(), Keywords.cINCLUDE)) + return false; + l.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE); + if (skipAll(l, Lexer.tNEWLINE).getType() != IToken.tPOUND) + return false; + if (!checkToken(l.nextToken(), Keywords.cENDIF)) + return false; + + return true; + } + + public static char[] detectIfNotDefinedIncludeEndif(Lexer l) { + l.saveState(); + try { + char[] guard= findNotDefined(l); + if (guard != null && findIncludeEndif(l)) + return guard; + } catch (OffsetLimitReachedException e) { + } finally { + l.restoreState(); + } + return null; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/InternalFileContent.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/InternalFileContent.java index ccfacf5ece7..2eabe13dea5 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/InternalFileContent.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/InternalFileContent.java @@ -13,6 +13,7 @@ package org.eclipse.cdt.internal.core.parser.scanner; import java.util.List; +import org.eclipse.cdt.core.dom.ast.IFileNomination; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective; import org.eclipse.cdt.core.index.IIndexFile; import org.eclipse.cdt.core.index.IIndexMacro; @@ -43,6 +44,8 @@ public class InternalFileContent extends FileContent { private final List fMacroDefinitions; private final List fUsingDirectives; private final String fFileLocation; + private final IFileNomination fPragmaOnceNomination; + private final List fNewPragmaOncePaths; private boolean fHeuristic; private boolean fIsSource= false; private List fFiles; @@ -52,10 +55,11 @@ public class InternalFileContent extends FileContent { * For skipping include files. * @param fileLocation the location of the file. * @param kind must be {@link InclusionKind#SKIP_FILE}. + * @param once * @throws IllegalArgumentException if fileLocation is null or the kind value is illegal for * this constructor. */ - public InternalFileContent(String fileLocation, InclusionKind kind) throws IllegalArgumentException { + public InternalFileContent(String fileLocation, InclusionKind kind, IFileNomination once) throws IllegalArgumentException { if (fileLocation == null || kind != InclusionKind.SKIP_FILE) { throw new IllegalArgumentException(); } @@ -64,6 +68,8 @@ public class InternalFileContent extends FileContent { fMacroDefinitions= null; fUsingDirectives= null; fSource= null; + fPragmaOnceNomination= once; + fNewPragmaOncePaths= null; } /** @@ -79,6 +85,8 @@ public class InternalFileContent extends FileContent { fSource= content; fMacroDefinitions= null; fUsingDirectives= null; + fPragmaOnceNomination= null; + fNewPragmaOncePaths= null; if (fFileLocation == null) { throw new IllegalArgumentException(); } @@ -89,16 +97,19 @@ public class InternalFileContent extends FileContent { * @param fileLocation the location of the file * @param macroDefinitions a list of macro definitions * @param files + * @param newPragmaOncePaths * @throws IllegalArgumentException in case the fileLocation or the macroDefinitions are null. */ public InternalFileContent(String fileLocation, List macroDefinitions, List usingDirectives, - List files) { + List files, List newPragmaOncePaths) { fKind= InclusionKind.FOUND_IN_INDEX; fFileLocation= fileLocation; fSource= null; fUsingDirectives= usingDirectives; fMacroDefinitions= macroDefinitions; fFiles= files; + fPragmaOnceNomination= null; + fNewPragmaOncePaths= newPragmaOncePaths; } /** @@ -155,6 +166,10 @@ public class InternalFileContent extends FileContent { public List getFilesIncluded() { return fFiles; } + + public List getPragmaOncePaths() { + return fNewPragmaOncePaths; + } /** * Returns whether this inclusion was found by a heuristics. @@ -183,6 +198,10 @@ public class InternalFileContent extends FileContent { fFoundOnPath= isp; } + public IFileNomination getPragmaOnceNomination() { + return fPragmaOnceNomination; + } + /** * This method is slow. Use only for debugging. */ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/InternalFileContentProvider.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/InternalFileContentProvider.java index 17c9e046bd3..b373a384f4e 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/InternalFileContentProvider.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/InternalFileContentProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 Wind River Systems, Inc. and others. + * Copyright (c) 2009, 2011 Wind River Systems, Inc. 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 @@ -7,14 +7,21 @@ * * Contributors: * Markus Schorn - initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.parser.scanner; import java.io.File; +import java.util.HashMap; +import java.util.Map; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; +import org.eclipse.cdt.core.dom.ast.IFileNomination; +import org.eclipse.cdt.core.index.IIndexFile; import org.eclipse.cdt.core.index.IIndexFileLocation; import org.eclipse.cdt.core.parser.IncludeFileContentProvider; import org.eclipse.cdt.internal.core.dom.IIncludeFileResolutionHeuristics; +import org.eclipse.cdt.internal.core.parser.IMacroDictionary; import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContent.InclusionKind; /** @@ -22,20 +29,24 @@ import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContent.Inclusio */ public abstract class InternalFileContentProvider extends IncludeFileContentProvider { private IIncludeFileResolutionHeuristics fIncludeResolutionHeuristics; + private final Map fPragmaOnce= new HashMap(); /** - * Check whether the specified inclusion exists. + * Checks whether the specified inclusion exists. */ public boolean getInclusionExists(String path) { return new File(path).exists(); } /** - * Create an InclusionContent object for the given location. - * return an inclusion content or null if the location does not exist. + * Creates an InclusionContent object for the given location. + * @param filePath the absolute location of the file. + * @param macroDictionary macros defined at the inclusion point. + * @return Returns an inclusion content, or null if the location does not exist. * @see InternalFileContent */ - public abstract InternalFileContent getContentForInclusion(String path); + public abstract InternalFileContent getContentForInclusion(String filePath, + IMacroDictionary macroDictionary); /** * Called only when used as a delegate of the index file content provider. @@ -46,28 +57,37 @@ public abstract class InternalFileContentProvider extends IncludeFileContentProv * Returns a file-content object of kind {@link InclusionKind#FOUND_IN_INDEX}, representing * the content from the context of the given file up to where the file actually gets included, * or null if this cannot be done. + * @param filePath the absolute location of the file. + * @param macroDictionary macros defined at the inclusion point. */ - public InternalFileContent getContentForContextToHeaderGap(String location) { + public InternalFileContent getContentForContextToHeaderGap(String filePath, + IMacroDictionary macroDictionary) { return null; } - /** - * Reports the path of the translation unit, such that it is known as included. - */ - public void reportTranslationUnitFile(String filePath) { + public void resetPragmaOnceTracking() { + fPragmaOnce.clear(); } - - /** - * Returns whether or not the file has been included, or null if the content provider - * does not track that. + + /** + * Reports detection of pragma once semantics. */ - public Boolean hasFileBeenIncludedInCurrentTranslationUnit(String location) { - return null; + public void reportPragmaOnceSemantics(String file, IFileNomination nomination) { + fPragmaOnce.put(file, nomination); } /** - * Returns a strategy for heuristically resolving includes, or null if this shall not - * be done. + * Returns {@link IASTPreprocessorIncludeStatement} or {@link IIndexFile}, in + * case the file has been included using pragma once semantics, + * or null otherwise. + */ + public IFileNomination isIncludedWithPragmaOnceSemantics(String filePath) { + return fPragmaOnce.get(filePath); + } + + /** + * Returns a strategy for heuristically resolving includes, or null if this shall + * not be done. */ public final IIncludeFileResolutionHeuristics getIncludeHeuristics() { return fIncludeResolutionHeuristics; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/Lexer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/Lexer.java index 2bf70b1e2f8..441c2907d1b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/Lexer.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/Lexer.java @@ -85,10 +85,14 @@ final public class Lexer implements ITokenSequence { private Token fToken; private Token fLastToken; - // for the few cases where we have to lookahead more than one character + // For the few cases where we have to lookahead more than one character private int fMarkOffset; private int fMarkEndOffset; private int fMarkPrefetchedChar; + // To store the entire state. + private boolean fMarkInsideIncludeDirective; + private Token fMarkToken; + private Token fMarkLastToken; public Lexer(char[] input, LexerOptions options, ILexerLog log, Object source) { this(new CharArray(input), 0, input.length, options, log, source); @@ -1256,4 +1260,22 @@ final public class Lexer implements ITokenSequence { restorePhase3(); return result; } + + public void saveState() { + fMarkOffset= fOffset; + fMarkEndOffset= fEndOffset; + fMarkPrefetchedChar= fCharPhase3; + fMarkInsideIncludeDirective= fInsideIncludeDirective; + fMarkToken= fToken; + fMarkLastToken= fLastToken; + } + + public void restoreState() { + fOffset= fMarkOffset; + fEndOffset= fMarkEndOffset; + fCharPhase3= fMarkPrefetchedChar; + fInsideIncludeDirective= fMarkInsideIncludeDirective; + fToken= fMarkToken; + fLastToken= fMarkLastToken; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationMap.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationMap.java index 23141ad545e..8033fadab4c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationMap.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationMap.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2011 Wind River Systems, Inc. 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 @@ -30,8 +30,12 @@ import org.eclipse.cdt.core.dom.ast.IASTProblem; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit.IDependencyTree; import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.IFileNomination; import org.eclipse.cdt.core.dom.ast.IMacroBinding; +import org.eclipse.cdt.core.parser.ISignificantMacros; +import org.eclipse.cdt.core.parser.util.CharArrayObjectMap; import org.eclipse.cdt.core.parser.util.CharArrayUtils; +import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.ASTNodeSpecification; import org.eclipse.cdt.internal.core.dom.parser.ASTProblem; import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions; @@ -130,7 +134,7 @@ public class LocationMap implements ILocationResolver { int nameEndNumber= getSequenceNumberForOffset(nameEndOffset); int endNumber= getSequenceNumberForOffset(endOffset); final ASTInclusionStatement inclusionStatement= - new ASTInclusionStatement(fTranslationUnit, startNumber, nameNumber, nameEndNumber, endNumber, name, filename, userInclude, true, heuristic); + new ASTInclusionStatement(fTranslationUnit, startNumber, nameNumber, nameEndNumber, endNumber, name, filename, userInclude, true, heuristic, null); fDirectives.add(inclusionStatement); fCurrentContext= new LocationCtxFile((LocationCtxContainer) fCurrentContext, filename, buffer, startOffset, endOffset, endNumber, inclusionStatement, isSource); fLastChildInsertionOffset= 0; @@ -205,7 +209,7 @@ public class LocationMap implements ILocationResolver { * Ends the current context. * @param locationCtx the current context, used to check whether caller and location map are still in sync. */ - public void popContext(ILocationCtx locationCtx) { + public void popContext(ILocationCtx locationCtx, CharArrayObjectMap sigMacros) { assert fCurrentContext == locationCtx; final LocationCtx child= fCurrentContext; final LocationCtx parent= (LocationCtx) fCurrentContext.getParent(); @@ -214,6 +218,18 @@ public class LocationMap implements ILocationResolver { fLastChildInsertionOffset= child.fEndOffsetInParent; parent.addChildSequenceLength(child.getSequenceLength()); } + if (sigMacros != null && locationCtx instanceof LocationCtxFile) { + ISignificantMacros sig = sigMacros.isEmpty() ? ISignificantMacros.NONE + : new SignificantMacros(sigMacros); + ASTInclusionStatement inc = ((LocationCtxFile) locationCtx).getInclusionStatement(); + if (inc != null) { + inc.setSignificantMacros(sig); + } else if (locationCtx == fRootContext) { + if (fTranslationUnit != null) { + fTranslationUnit.setSignificantMacros(sig); + } + } + } } /** @@ -227,13 +243,15 @@ public class LocationMap implements ILocationResolver { * @param active true when include appears in active code. */ public void encounterPoundInclude(int startOffset, int nameOffset, int nameEndOffset, int endOffset, - char[] name, String filename, boolean userInclude, boolean active, boolean heuristic) { + char[] name, String filename, boolean userInclude, boolean active, boolean heuristic, + IFileNomination nominationDelegate) { startOffset= getSequenceNumberForOffset(startOffset); nameOffset= getSequenceNumberForOffset(nameOffset); nameEndOffset= getSequenceNumberForOffset(nameEndOffset); endOffset= getSequenceNumberForOffset(endOffset); - fDirectives.add(new ASTInclusionStatement(fTranslationUnit, startOffset, nameOffset, - nameEndOffset, endOffset, name, filename, userInclude, active, heuristic)); + final ASTInclusionStatement inc = new ASTInclusionStatement(fTranslationUnit, startOffset, nameOffset, + nameEndOffset, endOffset, name, filename, userInclude, active, heuristic, nominationDelegate); + fDirectives.add(inc); } public void encounteredComment(int offset, int endOffset, boolean isBlockComment) { @@ -743,10 +761,39 @@ public class LocationMap implements ILocationResolver { } } - public void replacingFile(InternalFileContentProvider fileContentProvider, + public void parsingFile(InternalFileContentProvider fileContentProvider, InternalFileContent fileContent) { for (ISkippedIndexedFilesListener l : fSkippedFilesListeners) { - l.replacingFile(fileContentProvider, fileContent); + l.parsingFile(fileContentProvider, fileContent); } - } + } + + public IFileNomination reportPragmaOnceSemantics(ILocationCtx locationCtx) { + if (locationCtx == fRootContext) { + if (fTranslationUnit != null) { + fTranslationUnit.setPragmaOnceSemantics(true); + } + return fTranslationUnit; + } else if (locationCtx instanceof LocationCtxFile) { + ASTInclusionStatement stmt = ((LocationCtxFile) locationCtx).getInclusionStatement(); + if (stmt != null) { + stmt.setPragamOnceSemantics(true); + } + return stmt; + } + return null; + } + + public void endTranslationUnit(int endOffset, CharArrayObjectMap sigMacros) { + if (fTranslationUnit != null) { + int offset= getSequenceNumberForOffset(endOffset); + ((ASTNode) fTranslationUnit).setLength(offset); + + if (sigMacros != null) { + ISignificantMacros sig = sigMacros.isEmpty() ? ISignificantMacros.NONE + : new SignificantMacros(sigMacros); + fTranslationUnit.setSignificantMacros(sig); + } + } + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpander.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpander.java index b3a05055682..bb16a6a7867 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpander.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpander.java @@ -136,6 +136,7 @@ public class MacroExpander { private String fFixedCurrentFilename; private int fFixedLineNumber; private char[] fFixedInput; + private ScannerContext fReportMacros; public MacroExpander(ILexerLog log, CharArrayMap macroDictionary, LocationMap locationMap, LexerOptions lexOptions) { fDictionary= macroDictionary; @@ -147,8 +148,12 @@ public class MacroExpander { /** * Expects that the identifier has been consumed, stores the result in the list provided. + * @param scannerContext */ - public TokenList expand(ITokenSequence lexer, final boolean isPPCondition, PreprocessorMacro macro, Token identifier, boolean completionMode) throws OffsetLimitReachedException { + public TokenList expand(ITokenSequence lexer, final boolean isPPCondition, + PreprocessorMacro macro, Token identifier, boolean completionMode, + ScannerContext scannerContext) throws OffsetLimitReachedException { + fReportMacros= scannerContext; fImplicitMacroExpansions.clear(); fImageLocationInfos.clear(); @@ -180,6 +185,7 @@ public class MacroExpander { result= e.getParameterTokens().cloneTokens(); } postProcessTokens(result); + fReportMacros= null; return result; } @@ -193,6 +199,7 @@ public class MacroExpander { fFixedInput= beforeExpansion.toCharArray(); fFixedCurrentFilename= filePath; fFixedLineNumber= lineNumber; + fReportMacros= null; Lexer lexer= new Lexer(fFixedInput, fLexOptions, fLog, this); try { @@ -240,6 +247,9 @@ public class MacroExpander { IdentityHashMap forbidden, TokenSource input, TokenList result, MacroExpansionTracker tracker) throws OffsetLimitReachedException { + if (fReportMacros != null) + fReportMacros.significantMacro(macro); + if (macro.isFunctionStyle()) { final int paramCount = macro.getParameterPlaceholderList().length; final TokenSource[] argInputs= new TokenSource[paramCount]; @@ -351,6 +361,13 @@ public class MacroExpander { protect= true; } else if (macro == null || (macro.isFunctionStyle() && !input.findLParenthesis())) { // Tricky: Don't mark function-style macros if you don't find the left parenthesis + if (fReportMacros != null) { + if (macro == null) { + fReportMacros.significantMacroUndefined(image); + } else { + fReportMacros.significantMacro(macro); + } + } result.append(t); } else if (forbidden.containsKey(macro)) { t.setType(CPreprocessor.tEXPANDED_IDENTIFIER); // prevent any further expansion diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MultiMacroExpansionExplorer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MultiMacroExpansionExplorer.java index a307d673c4b..89deea45e9e 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MultiMacroExpansionExplorer.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MultiMacroExpansionExplorer.java @@ -22,6 +22,7 @@ import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNodeSelector; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorElifStatement; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfStatement; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; @@ -48,13 +49,14 @@ public class MultiMacroExpansionExplorer extends MacroExpansionExplorer { fOffset= offset; fLength= length; } - public int getNodeOffset() {return fOffset;} - public int getNodeLength() {return fLength;} - public String getFileName() {return fFilePath;} + public int getNodeOffset() { return fOffset; } + public int getNodeLength() { return fLength; } + public String getFileName() { return fFilePath; } - public int getStartingLineNumber() {return 0;} - public int getEndingLineNumber() {return 0;} - public IASTFileLocation asFileLocation() {return this;} + public int getStartingLineNumber() { return 0; } + public int getEndingLineNumber() { return 0; } + public IASTFileLocation asFileLocation() { return this; } + public IASTPreprocessorIncludeStatement getContextInclusionStatement() { return null; } } private final char[] fSource; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ScannerContext.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ScannerContext.java index b032956b7d8..8123be6e038 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ScannerContext.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ScannerContext.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2009 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2011 Wind River Systems, Inc. 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 @@ -12,8 +12,12 @@ package org.eclipse.cdt.internal.core.parser.scanner; import java.util.ArrayList; +import org.eclipse.cdt.core.dom.ast.IMacroBinding; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.core.parser.IToken; import org.eclipse.cdt.core.parser.OffsetLimitReachedException; +import org.eclipse.cdt.core.parser.util.CharArrayObjectMap; +import org.eclipse.cdt.core.parser.util.CharArraySet; /** * Represents part of the input to the preprocessor. This may be a file or the result of a macro expansion. @@ -43,6 +47,7 @@ final class ScannerContext { } private CodeState fInactiveState= CodeState.eSkipInactive; + private final int fDepth; private final ILocationCtx fLocationCtx; private final ScannerContext fParent; private final Lexer fLexer; @@ -51,19 +56,32 @@ final class ScannerContext { private CodeState fCurrentState= CodeState.eActive; private IncludeSearchPathElement fFoundOnPath; private String fFoundViaDirective; + private CharArraySet fInternalModifications; + private CharArrayObjectMap fSignificantMacros; + private boolean fPragmaOnce; + /** * @param ctx * @param parent context to be used after this context is done. */ - public ScannerContext(ILocationCtx ctx, ScannerContext parent, Lexer lexer) { + public ScannerContext(ILocationCtx ctx, ScannerContext parent, Lexer lexer, + boolean trackSignificantMacros) { fLocationCtx= ctx; fParent= parent; fLexer= lexer; + fDepth = parent == null ? 0 : parent.fDepth+1; + if (trackSignificantMacros) { + fInternalModifications= new CharArraySet(5); + fSignificantMacros= new CharArrayObjectMap(5); + } else { + fInternalModifications= null; + fSignificantMacros= null; + } } public ScannerContext(ILocationCtx ctx, ScannerContext parent, TokenList tokens) { - this(ctx, parent, (Lexer) null); + this(ctx, parent, null, false); fTokens= tokens.first(); fInactiveState= CodeState.eSkipInactive; // no branches in result of macro expansion } @@ -87,6 +105,13 @@ final class ScannerContext { return fParent; } + /** + * Returns the depth of this context, equals the number of parents of this context. + */ + public final int getDepth() { + return fDepth; + } + /** * Returns the lexer for this context. */ @@ -297,4 +322,130 @@ final class ScannerContext { fFoundOnPath= foundOnPath; fFoundViaDirective= viaDirective; } + + public void setPragmaOnce() { + fPragmaOnce= true; + } + + public void internalModification(char[] macroName) { + if (fInternalModifications != null) + fInternalModifications.put(macroName); + } + + public boolean hasInternalModification(char[] namechars) { + return fInternalModifications != null && fInternalModifications.containsKey(namechars); + } + + public void significantMacro(IMacroBinding macro) { + if (fPragmaOnce) + return; + final char[] macroName= macro.getNameCharArray(); + if (fInternalModifications != null && !fInternalModifications.containsKey(macroName)) { + fSignificantMacros.put(macroName, macro.getExpansion()); + } + } + + public void significantMacroDefined(char[] macroName) { + if (fPragmaOnce) + return; + if (fInternalModifications != null && !fInternalModifications.containsKey(macroName)) { + addSignificantMacroDefined(macroName); + } + } + + private void addSignificantMacroDefined(char[] macroName) { + char[] old= fSignificantMacros.put(macroName, SignificantMacros.DEFINED); + if (old != null && old != SignificantMacros.DEFINED) { + // Put back more detailed condition + fSignificantMacros.put(macroName, old); + } + } + + public void significantMacroUndefined(char[] macroName) { + if (fPragmaOnce) + return; + if (fInternalModifications != null && !fInternalModifications.containsKey(macroName)) { + fSignificantMacros.put(macroName, SignificantMacros.UNDEFINED); + } + } + + public void addSignificantInclusion(String path) { + final char[] inc = path.toCharArray(); + if (fInternalModifications != null && !fInternalModifications.containsKey(inc)) { + fSignificantMacros.put(inc, SignificantMacros.INCLUDED); + } + } + + public CharArrayObjectMap getSignificantMacros() { + return fSignificantMacros; + } + + public void propagateSignificantMacros() { + if (fInternalModifications == null) + return; + + if (fParent != null) { + final CharArraySet local = fParent.fInternalModifications; + if (local != null) { + final CharArrayObjectMap significant = fParent.fSignificantMacros; + for (int i=0; i as an array of characters and to decode + * it back. + * + * The map is encoded as: + * <number_of_entries>,<key1><value1>...<keyN><valueN>. + *

+ * Each string is encoded as: <number_of_characters>,<characters>. + * A null string is encoded as a single comma. + */ +public class SignificantMacros implements ISignificantMacros { + public static final char[] UNDEFINED = {}; + public static final char[] DEFINED = {}; + public static final char[] INCLUDED = {}; + private static final int ENCODED_UNDEFINED = Character.MAX_VALUE; + private static final int ENCODED_DEFINED = Character.MAX_VALUE-1; + private static final int ENCODED_INCLUDED = Character.MAX_VALUE-2; + private static final Comparator SORTER = new Comparator() { + public int compare(Object o1, Object o2) { + return CharArrayUtils.compare((char[])o1, (char[])o2); + } + }; + + private final char[] fEncoded; + private int fHash; + + public SignificantMacros(char[] encoded) { + assert encoded != null; + fEncoded= encoded; + } + + public SignificantMacros(CharArrayObjectMap sigMacros) { + fEncoded= encode(sigMacros); + } + + private char[] encode(CharArrayObjectMap sigMacros) { + StringBuilder buffer= new StringBuilder(); + Object[] keys= sigMacros.keyArray(); + Arrays.sort(keys, SORTER); + for (Object key : keys) { + char[] name= (char[]) key; + char[] value= sigMacros.get(name); + buffer.append((char) name.length).append(name); + if (value == DEFINED) { + buffer.append((char) ENCODED_DEFINED); + } else if (value == UNDEFINED) { + buffer.append((char) ENCODED_UNDEFINED); + } else if (value == INCLUDED) { + buffer.append((char) ENCODED_INCLUDED); + } else { + buffer.append((char) value.length).append(value); + } + } + int len= buffer.length(); + char[] result= new char[len]; + buffer.getChars(0, len, result, 0); + return result; + } + + @Override + public int hashCode() { + int h = fHash; + if (h == 0) { + char val[] = fEncoded; + int len = fEncoded.length; + for (int i = 0; i < len; i++) { + h = 31*h + val[i]; + } + fHash = h; + } + return h; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof SignificantMacros + && hashCode() == obj.hashCode() + && CharArrayUtils.equals(fEncoded, ((SignificantMacros) obj).fEncoded); + } + + public boolean accept(IVisitor visitor) { + final char[] encoded = fEncoded; + final int len = encoded.length; + int i= 0; + while (i < len) { + final int len1 = encoded[i++]; + int v= i + len1; + if (v >= len) + break; + + char[] macro= extract(encoded, i, len1); + final int len2 = encoded[v++]; + switch(len2) { + case ENCODED_UNDEFINED: + i= v; + if (!visitor.visitUndefined(macro)) + return false; + break; + case ENCODED_DEFINED: + i= v; + if (!visitor.visitDefined(macro)) + return false; + break; + case ENCODED_INCLUDED: + i= v; + if (!visitor.visitIncluded(macro)) + return false; + break; + default: + i= v+len2; + if (i > len) + break; + if (!visitor.visitValue(macro, extract(encoded, v, len2))) + return false; + break; + } + } + return true; + } + + public char[] extract(final char[] source, int from, final int length) { + char[] value= new char[length]; + System.arraycopy(source, from, value, 0, length); + return value; + } + + public char[] encode() { + return fEncoded; + } + + /** + * For debugging purposes. + */ + @SuppressWarnings("nls") + @Override + public String toString() { + final StringBuilder buf= new StringBuilder(); + buf.append('{'); + accept(new IVisitor() { + public boolean visitValue(char[] macro, char[] value) { + buf.append(macro).append('=').append(value).append(','); + return true; + } + public boolean visitUndefined(char[] macro) { + buf.append(macro).append('=').append("null,"); + return true; + } + public boolean visitIncluded(char[] path) { + buf.append(path).append(','); + return true; + } + public boolean visitDefined(char[] macro) { + buf.append(macro).append('=').append("*,"); + return true; + } + }); + int buflen = buf.length(); + if (buflen > 1) + buf.setLength(buflen-1); + buf.append('}'); + return buf.toString(); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/AbstractIndexerTask.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/AbstractIndexerTask.java index 52c0ed51bdc..09380260191 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/AbstractIndexerTask.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/AbstractIndexerTask.java @@ -15,7 +15,6 @@ package org.eclipse.cdt.internal.core.pdom; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -23,11 +22,9 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IPDOMIndexerTask; -import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit.IDependencyTree; @@ -42,21 +39,21 @@ import org.eclipse.cdt.core.index.IndexLocationFactory; import org.eclipse.cdt.core.model.AbstractLanguage; import org.eclipse.cdt.core.model.ILanguage; import org.eclipse.cdt.core.parser.FileContent; -import org.eclipse.cdt.core.parser.IExtendedScannerInfo; import org.eclipse.cdt.core.parser.IParserLogService; import org.eclipse.cdt.core.parser.IScannerInfo; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.core.parser.IncludeFileContentProvider; import org.eclipse.cdt.core.parser.ParserUtil; import org.eclipse.cdt.core.parser.ScannerInfo; import org.eclipse.cdt.internal.core.dom.IIncludeFileResolutionHeuristics; +import org.eclipse.cdt.internal.core.index.FileContentKey; import org.eclipse.cdt.internal.core.index.IIndexFragment; 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.scanner.InternalFileContentProvider; -import org.eclipse.cdt.internal.core.parser.scanner.StreamHasher; import org.eclipse.cdt.utils.EFSExtensionManager; -import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; @@ -74,55 +71,168 @@ public abstract class AbstractIndexerTask extends PDOMWriter { skip, useDefaultLanguage, useAlternateLanguage, useBoth } private static final int MAX_ERRORS = 500; - - private static class FileKey { - final URI fUri; + + private static enum UpdateKind {REQUIRED_SOURCE, REQUIRED_HEADER, OTHER_HEADER} + private static class LinkageTask { final int fLinkageID; + private final Map fLocationTasks; - public FileKey(int linkageID, URI uri) { - fUri= uri; + LinkageTask(int linkageID) { fLinkageID= linkageID; + fLocationTasks= new HashMap(); + } + + boolean requestUpdate(IIndexFileLocation ifl, IIndexFragmentFile ifile, Object tu, + UpdateKind kind) { + LocationTask locTask= fLocationTasks.get(ifl); + if (locTask == null) { + locTask= new LocationTask(); + fLocationTasks.put(ifl, locTask); + } + return locTask.requestUpdate(ifile, tu, kind); } - @Override - public int hashCode() { - return fUri.hashCode() * 31 + fLinkageID; + LocationTask find(IIndexFileLocation ifl) { + return fLocationTasks.get(ifl); } - @Override - public boolean equals(Object obj) { - FileKey other = (FileKey) obj; - return fLinkageID == other.fLinkageID && fUri.equals(other.fUri); + LocationTask cacheIndexFiles(IIndexFileLocation ifl, IIndexFile[] files) { + final LocationTask locTask = new LocationTask(); + locTask.addIndexFiles(files); + fLocationTasks.put(ifl, locTask); + return locTask; } } + private static class LocationTask { + private boolean fAddRequested; + Object fTu; + UpdateKind fKind= UpdateKind.OTHER_HEADER; + private List fIndexFiles= Collections.emptyList(); + + /** + * Requests the update of a file, returns whether the total count needs to be updated. + */ + boolean requestUpdate(IIndexFragmentFile ifile, Object tu, UpdateKind kind) { + if (tu != null) + fTu= tu; + if (kind != null) + fKind= kind; + + if (ifile == null) { + assert fIndexFiles.isEmpty(); + final boolean count= !fAddRequested; + fAddRequested= true; + return count; + } + + return addVersionTask(ifile).requestUpdate(); + } + + public void addIndexFiles(IIndexFile[] files) { + assert fIndexFiles.isEmpty() && !fAddRequested; + switch(files.length) { + case 0: + break; + case 1: + fIndexFiles= Collections.singletonList(new FileVersionTask(files[0], false)); + break; + default: + fIndexFiles= new ArrayList(files.length); + for (IIndexFile iIndexFile : files) { + fIndexFiles.add(new FileVersionTask(iIndexFile, false)); + } + break; + } + } + + private FileVersionTask addVersionTask(IIndexFile ifile) { + FileVersionTask fc= findVersion(ifile); + if (fc != null) + return fc; + + fc= new FileVersionTask(ifile, fAddRequested); + fAddRequested= false; + + switch(fIndexFiles.size()) { + case 0: + fIndexFiles= Collections.singletonList(fc); + break; + case 1: + List newList= new ArrayList(2); + newList.add(fIndexFiles.get(0)); + newList.add(fc); + fIndexFiles= newList; + break; + default: + fIndexFiles.add(fc); + break; + } + return fc; + } + + private FileVersionTask findVersion(IIndexFile ifile) { + for (FileVersionTask fc : fIndexFiles) { + if (fc.fIndexFile.equals(ifile)) + return fc; + } + return null; + } + + public FileVersionTask findVersion(ISignificantMacros sigMacros) throws CoreException { + for (FileVersionTask fc : fIndexFiles) { + if (sigMacros.equals(fc.fIndexFile.getSignificantMacros())) + return fc; + } + return null; + } + + public boolean isCompleted() { + if (fIndexFiles.isEmpty()) + return !fAddRequested; + + for (FileVersionTask fc : fIndexFiles) { + if (fc.fUpdateRequested) + return false; + } + return true; + } + } + + public static class FileVersionTask { + private final IIndexFile fIndexFile; + private boolean fUpdateRequested; + + public FileVersionTask(IIndexFile ifile, boolean requestUpdate) { + fIndexFile= ifile; + fUpdateRequested= requestUpdate; + } + + public boolean requestUpdate() { + boolean result= !fUpdateRequested; + fUpdateRequested= true; + return result; + } + + public void setUpdated() { + fUpdateRequested= false; + } + } + public static class IndexFileContent { - private IIndexFile fIndexFile; - private boolean fRequestUpdate; - private boolean fRequestIsCounted= true; - private boolean fIsUpdated; private Object[] fPreprocessingDirectives; private ICPPUsingDirective[] fDirectives; - public IndexFileContent() { - fRequestIsCounted = true; + public IndexFileContent(IIndexFile ifile) throws CoreException { + setPreprocessorDirectives(ifile.getIncludes(), ifile.getMacros()); + setUsingDirectives(ifile.getUsingDirectives()); } public Object[] getPreprocessingDirectives() throws CoreException { - if (fPreprocessingDirectives == null) { - if (fIndexFile == null) - return new Object[0]; - setPreprocessorDirectives(fIndexFile.getIncludes(), fIndexFile.getMacros()); - } return fPreprocessingDirectives; } public ICPPUsingDirective[] getUsingDirectives() throws CoreException { - if (fDirectives == null) { - if (fIndexFile == null) - return ICPPUsingDirective.EMPTY_ARRAY; - setUsingDirectives(fIndexFile.getUsingDirectives()); - } return fDirectives; } @@ -134,11 +244,6 @@ public abstract class AbstractIndexerTask extends PDOMWriter { fDirectives= usingDirectives; } - public void clearCaches() { - fPreprocessingDirectives= null; - fDirectives= null; - } - public static Object[] merge(IIndexInclude[] includes, IIndexMacro[] macros) throws CoreException { Object[] merged= new Object[includes.length + macros.length]; int i= 0; @@ -177,11 +282,11 @@ public abstract class AbstractIndexerTask extends PDOMWriter { private int fUpdateFlags= IIndexManager.UPDATE_ALL; private UnusedHeaderStrategy fIndexHeadersWithoutContext= UnusedHeaderStrategy.useDefaultLanguage; private boolean fIndexFilesWithoutConfiguration= true; - private HashMap fFileInfos= new HashMap(); - + private List fRequestsPerLinkage= new ArrayList(); + private Map fIndexContentCache= new HashMap(); + private Object[] fFilesToUpdate; private List fFilesToRemove = new ArrayList(); - private List fFilesUpFront= new ArrayList(); private int fASTOptions; private int fForceNumberFiles= 0; @@ -197,7 +302,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { */ private final LinkedList fUrgentTasks; boolean fTaskCompleted; - + private IndexerProgress fInfo= new IndexerProgress(); public AbstractIndexerTask(Object[] filesToUpdate, Object[] filesToRemove, IndexerInputAdapter resolver, boolean fastIndexer) { super(resolver); @@ -228,8 +333,8 @@ public abstract class AbstractIndexerTask extends PDOMWriter { fUpdateFlags= flags; } + // TODO(197989) remove public final void setParseUpFront(String[] astFilePaths) { - fFilesUpFront.addAll(Arrays.asList(astFilePaths)); } public final void setForceFirstFiles(int number) { @@ -240,6 +345,30 @@ public abstract class AbstractIndexerTask extends PDOMWriter { fFileSizeLimit= limit; } + /** + * @see IPDOMIndexerTask#acceptUrgentTask(IPDOMIndexerTask) + */ + public synchronized boolean acceptUrgentTask(IPDOMIndexerTask urgentTask) { + if (!(urgentTask instanceof AbstractIndexerTask)) { + return false; + } + AbstractIndexerTask task = (AbstractIndexerTask) urgentTask; + if (task.fIsFastIndexer != fIsFastIndexer || + task.fIndexFilesWithoutConfiguration != fIndexFilesWithoutConfiguration || + (fIndexFilesWithoutConfiguration && task.fIndexHeadersWithoutContext != fIndexHeadersWithoutContext) || + fTaskCompleted) { + // Reject the urgent work since this task is not capable of doing it, or it's too late. + return false; + } + if (task.fFilesToUpdate.length > + (fFilesToUpdate != null ? fFilesToUpdate.length : getProgressInformation().fRequestedFilesCount)) { + // Reject the urgent work since it's too heavy for this task. + return false; + } + fUrgentTasks.add(task); + return true; + } + protected abstract IWritableIndex createIndex(); protected abstract IIncludeFileResolutionHeuristics createIncludeHeuristics(); protected abstract IncludeFileContentProvider createReaderFactory(); @@ -253,22 +382,47 @@ public abstract class AbstractIndexerTask extends PDOMWriter { return new ScannerInfo(); } - protected String getASTPathForParsingUpFront() { - return "______"; //$NON-NLS-1$ + /** + * Makes a copy of the current progress information and returns it. + * @since 4.0 + */ + public IndexerProgress getProgressInformation() { + synchronized (fInfo) { + return new IndexerProgress(fInfo); + } } - private final IASTTranslationUnit createAST(String code, AbstractLanguage lang, IScannerInfo scanInfo, - int options, IProgressMonitor monitor) throws CoreException { - String dummyName= getASTPathForParsingUpFront(); - if (dummyName != null) { - IIndexFileLocation dummyLoc= fResolver.resolveASTPath(dummyName); - setIndexed(lang.getLinkageID(), dummyLoc); - FileContent codeReader= FileContent.create(dummyName, code.toCharArray()); - return createAST(lang, codeReader, scanInfo, options, false, monitor); + /** + * Updates current progress information with the provided delta. + */ + private final void updateFileCount(int sources, int primaryHeader, int header) { + synchronized (fInfo) { + fInfo.fCompletedSources += sources; + fInfo.fPrimaryHeaderCount += primaryHeader; + fInfo.fCompletedHeaders += header; } - return null; } + private final void reportFile(boolean requested, UpdateKind kind) { + if (requested) { + if (kind == UpdateKind.REQUIRED_SOURCE) { + updateFileCount(1, 0, 0); + } else { + updateFileCount(0, 1, 1); + } + } else { + updateFileCount(0, 0, 1); + } + } + + /** + * Updates current progress information with the provided delta. + */ + private final void incrementRequestedFilesCount(int delta) { + synchronized (fInfo) { + fInfo.fRequestedFilesCount += delta; + } + } private final IASTTranslationUnit createAST(Object tu, AbstractLanguage language, FileContent codeReader, IScannerInfo scanInfo, int options, boolean inContext, IProgressMonitor pm) throws CoreException { @@ -278,11 +432,6 @@ public abstract class AbstractIndexerTask extends PDOMWriter { if (fResolver.isSourceUnit(tu)) { options |= ILanguage.OPTION_IS_SOURCE_UNIT; } - return createAST(language, codeReader, scanInfo, options, inContext, pm); - } - - private final IASTTranslationUnit createAST(AbstractLanguage language, FileContent codeReader, - IScannerInfo scanInfo, int options, boolean inContext, IProgressMonitor pm) throws CoreException { if (fFileSizeLimit > 0 && fResolver.getFileSize(codeReader.getFileLocation()) > fFileSizeLimit) { if (fShowActivity) { trace("Indexer: Skipping large file " + codeReader.getFileLocation()); //$NON-NLS-1$ @@ -300,22 +449,17 @@ public abstract class AbstractIndexerTask extends PDOMWriter { } else { fCodeReaderFactory= fileContentProvider; } + fCodeReaderFactory.setIncludeResolutionHeuristics(createIncludeHeuristics()); } else if (fIsFastIndexer) { ((IndexBasedFileContentProvider) fCodeReaderFactory).setLinkage(language.getLinkageID()); } - fCodeReaderFactory.setIncludeResolutionHeuristics(createIncludeHeuristics()); - try { - IASTTranslationUnit ast= language.getASTTranslationUnit(codeReader, scanInfo, fCodeReaderFactory, - fIndex, options, getLogService()); - if (pm.isCanceled()) { - return null; - } - return ast; - } finally { - if (fIsFastIndexer) { - ((IndexBasedFileContentProvider) fCodeReaderFactory).cleanupAfterTranslationUnit(); - } + + IASTTranslationUnit ast= language.getASTTranslationUnit(codeReader, scanInfo, fCodeReaderFactory, + fIndex, options, getLogService()); + if (pm.isCanceled()) { + return null; } + return ast; } private InternalFileContentProvider createInternalFileContentProvider() { @@ -354,7 +498,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { try { try { // Split into sources and headers, remove excluded sources. - HashMap> files= new HashMap>(); + HashMap> files= new HashMap>(); final ArrayList indexFilesToRemove= new ArrayList(); extractFiles(files, indexFilesToRemove, monitor); @@ -362,13 +506,15 @@ public abstract class AbstractIndexerTask extends PDOMWriter { // Remove files from index removeFilesInIndex(fFilesToRemove, indexFilesToRemove, monitor); - - parseFilesUpFront(monitor); - HashMap> moreFiles= null; + HashMap> moreFiles= null; while (true) { for (int linkageID : getLinkagesToParse()) { - parseLinkage(linkageID, files, monitor); + final List filesForLinkage = files.get(linkageID); + if (filesForLinkage != null) { + parseLinkage(linkageID, filesForLinkage, monitor); + fIndexContentCache.clear(); + } if (hasUrgentTasks()) break; } @@ -390,8 +536,8 @@ public abstract class AbstractIndexerTask extends PDOMWriter { if (moreFiles == null) { moreFiles = files; } else { - for (Map.Entry> entry : files.entrySet()) { - List list= moreFiles.get(entry.getKey()); + for (Map.Entry> entry : files.entrySet()) { + List list= moreFiles.get(entry.getKey()); if (list == null) { moreFiles.put(entry.getKey(), entry.getValue()); } else { @@ -400,7 +546,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { } } // Extract files from the urgent task. - files = new HashMap>(); + files = new HashMap>(); fFilesToUpdate = urgentTask.fFilesToUpdate; fForceNumberFiles = urgentTask.fForceNumberFiles; fFilesToRemove = urgentTask.fFilesToRemove; @@ -427,31 +573,6 @@ public abstract class AbstractIndexerTask extends PDOMWriter { } } - /** - * @see IPDOMIndexerTask#acceptUrgentTask(IPDOMIndexerTask) - */ - public synchronized boolean acceptUrgentTask(IPDOMIndexerTask urgentTask) { - if (!(urgentTask instanceof AbstractIndexerTask)) { - return false; - } - AbstractIndexerTask task = (AbstractIndexerTask) urgentTask; - if (!task.fFilesUpFront.isEmpty() || - task.fIsFastIndexer != fIsFastIndexer || - task.fIndexFilesWithoutConfiguration != fIndexFilesWithoutConfiguration || - (fIndexFilesWithoutConfiguration && task.fIndexHeadersWithoutContext != fIndexHeadersWithoutContext) || - fTaskCompleted) { - // Reject the urgent work since this task is not capable of doing it, or it's too late. - return false; - } - if (task.fFilesToUpdate.length > - (fFilesToUpdate != null ? fFilesToUpdate.length : getProgressInformation().fRequestedFilesCount)) { - // Reject the urgent work since it's too heavy for this task. - return false; - } - fUrgentTasks.add(task); - return true; - } - private void setResume(boolean value) throws InterruptedException, CoreException { fIndex.acquireWriteLock(1); try { @@ -461,12 +582,11 @@ public abstract class AbstractIndexerTask extends PDOMWriter { } } - private void extractFiles(HashMap> files, List iFilesToRemove, + private void extractFiles(HashMap> files, List iFilesToRemove, IProgressMonitor monitor) throws CoreException { final boolean forceAll= (fUpdateFlags & IIndexManager.UPDATE_ALL) != 0; final boolean checkTimestamps= (fUpdateFlags & IIndexManager.UPDATE_CHECK_TIMESTAMPS) != 0; final boolean checkFileContentsHash = (fUpdateFlags & IIndexManager.UPDATE_CHECK_CONTENTS_HASH) != 0; - final boolean checkConfig= (fUpdateFlags & IIndexManager.UPDATE_CHECK_CONFIGURATION) != 0; int count= 0; int forceFirst= fForceNumberFiles; @@ -480,39 +600,33 @@ public abstract class AbstractIndexerTask extends PDOMWriter { continue; final IIndexFragmentFile[] indexFiles= fIndex.getWritableFiles(ifl); - if (!fResolver.isIndexedOnlyIfIncluded(tu)) { - final boolean isSourceUnit= fResolver.isSourceUnit(tu); - final boolean isExcludedSource= isSourceUnit && !fIndexFilesWithoutConfiguration && !fResolver.isFileBuildConfigured(tu); - - if ((isSourceUnit && !isExcludedSource) || fIndexHeadersWithoutContext != UnusedHeaderStrategy.skip || - fResolver.isIndexedUnconditionally(ifl)) { - // Headers or sources required with a specific linkage - AbstractLanguage[] langs= fResolver.getLanguages(tu, fIndexHeadersWithoutContext == UnusedHeaderStrategy.useBoth); - for (AbstractLanguage lang : langs) { - int linkageID = lang.getLinkageID(); - IIndexFragmentFile ifile= getFile(linkageID, indexFiles); - if (ifile == null || !ifile.hasContent()) { - store(tu, linkageID, isSourceUnit, files); - requestUpdate(linkageID, ifl, null); - count++; - } else { - takeFile(ifile, indexFiles); - boolean update= false; - if (checkConfig) { - update= isSourceUnit ? isSourceUnitConfigChange(tu, ifile) : isHeaderConfigChange(tu, ifile); - } - update= update || force || isModified(checkTimestamps, checkFileContentsHash, ifl, tu, ifile); - if (update) { - requestUpdate(linkageID, ifl, ifile); - store(tu, linkageID, isSourceUnit, files); + final boolean isSourceUnit= fResolver.isSourceUnit(tu); + if (isRequiredInIndex(tu, ifl, isSourceUnit)) { + // Headers or sources required with a specific linkage + final UpdateKind updateKind = isSourceUnit ? UpdateKind.REQUIRED_SOURCE : UpdateKind.REQUIRED_HEADER; + AbstractLanguage[] langs= fResolver.getLanguages(tu, fIndexHeadersWithoutContext == UnusedHeaderStrategy.useBoth); + for (AbstractLanguage lang : langs) { + int linkageID = lang.getLinkageID(); + boolean foundInLinkage = false; + for (int i = 0; i < indexFiles.length; i++) { + IIndexFragmentFile ifile = indexFiles[i]; + if (ifile != null && ifile.getLinkageID() == linkageID && ifile.hasContent()) { + foundInLinkage = true; + indexFiles[i]= null; // Take the file. + boolean update= force || isModified(checkTimestamps, checkFileContentsHash, ifl, tu, ifile); + if (update && requestUpdate(linkageID, ifl, ifile, tu, updateKind)) { count++; } } } + if (!foundInLinkage && requestUpdate(linkageID, ifl, null, tu, updateKind)) { + count++; + } + store(linkageID, ifl, files); } } - // handle other files present in index + // Handle other files present in index. for (IIndexFragmentFile ifile : indexFiles) { if (ifile != null) { IIndexInclude ctx= ifile.getParsedInContext(); @@ -520,15 +634,8 @@ public abstract class AbstractIndexerTask extends PDOMWriter { iFilesToRemove.add(ifile); count++; } else { - boolean update= false; - if (checkConfig) { - update= isHeaderConfigChange(tu, ifile); - } - update= update || force || isModified(checkTimestamps, checkFileContentsHash, ifl, tu, ifile); - if (update) { - final int linkageID = ifile.getLinkageID(); - requestUpdate(linkageID, ifl, ifile); - store(tu, linkageID, false, files); + boolean update= force || isModified(checkTimestamps, checkFileContentsHash, ifl, tu, ifile); + if (update && requestUpdate(ifile.getLinkageID(), ifl, ifile, tu, UpdateKind.OTHER_HEADER)) { count++; } } @@ -541,6 +648,27 @@ public abstract class AbstractIndexerTask extends PDOMWriter { } } + private boolean isRequiredInIndex(Object tu, IIndexFileLocation ifl, boolean isSourceUnit) { + // External files are never required + if (fResolver.isIndexedOnlyIfIncluded(tu)) + return false; + + // User preference to require all + if (fIndexHeadersWithoutContext != UnusedHeaderStrategy.skip) + return true; + + // File required because it is open in the editor. + if (fResolver.isIndexedUnconditionally(ifl)) + return true; + + // Source file + if (isSourceUnit) { + if (fIndexFilesWithoutConfiguration || fResolver.isFileBuildConfigured(tu)) + return true; + } + return false; + } + private boolean isModified(boolean checkTimestamps, boolean checkFileContentsHash, IIndexFileLocation ifl, Object tu, IIndexFragmentFile file) throws CoreException { if (checkTimestamps) { @@ -555,78 +683,79 @@ public abstract class AbstractIndexerTask extends PDOMWriter { return false; } - private void requestUpdate(int linkageID, IIndexFileLocation ifl, IIndexFragmentFile ifile) { - FileKey key= new FileKey(linkageID, ifl.getURI()); - IndexFileContent info= fFileInfos.get(key); - if (info == null) { - info= createFileInfo(key, null); - } - info.fIndexFile= ifile; - info.fRequestUpdate= true; - info.fIsUpdated= false; + private boolean requestUpdate(int linkageID, IIndexFileLocation ifl, IIndexFragmentFile ifile, Object tu, UpdateKind kind) { + LinkageTask fileMap= createRequestMap(linkageID); + return fileMap.requestUpdate(ifl, ifile, tu, kind); } - private void setIndexed(int linkageID, IIndexFileLocation ifl) { - FileKey key= new FileKey(linkageID, ifl.getURI()); - IndexFileContent info= fFileInfos.get(key); - if (info == null) { - info= createFileInfo(key, null); + private LinkageTask createRequestMap(int linkageID) { + LinkageTask map= findRequestMap(linkageID); + if (map == null) { + map= new LinkageTask(linkageID); + fRequestsPerLinkage.add(map); } - info.fIsUpdated= true; - info.clearCaches(); + return map; } - private IndexFileContent createFileInfo(FileKey key, IIndexFile ifile) { - IndexFileContent info = new IndexFileContent(); - fFileInfos.put(key, info); - info.fIndexFile= ifile; - return info; - } - - private IndexFileContent getFileInfo(int linkageID, IIndexFileLocation ifl) { - FileKey key= new FileKey(linkageID, ifl.getURI()); - return fFileInfos.get(key); - } - - private boolean isSourceUnitConfigChange(Object tu, IIndexFragmentFile ifile) { - return false; - } - - private boolean isHeaderConfigChange(Object tu, IIndexFragmentFile ifile) { - return false; - } - - private IIndexFragmentFile getFile(int linkageID, IIndexFragmentFile[] indexFiles) throws CoreException { - for (IIndexFragmentFile ifile : indexFiles) { - if (ifile != null && ifile.getLinkageID() == linkageID) { - return ifile; - } + private LinkageTask findRequestMap(int linkageID) { + for (LinkageTask map : fRequestsPerLinkage) { + if (map.fLinkageID == linkageID) + return map; } return null; } - - private void takeFile(IIndexFragmentFile ifile, IIndexFragmentFile[] indexFiles) { - for (int i = 0; i < indexFiles.length; i++) { - if (indexFiles[i] == ifile) { - indexFiles[i]= null; - return; + + private boolean needToStoreInIndex(int linkageID, IIndexFileLocation ifl, ISignificantMacros sigMacros) throws CoreException { + LinkageTask map = findRequestMap(linkageID); + if (map != null) { + LocationTask locTask= map.find(ifl); + if (locTask != null) { + FileVersionTask task = locTask.findVersion(sigMacros); + if (task != null) { + return task.fUpdateRequested; + } } } - } - - private void store(Object tu, int linkageID, boolean isSourceUnit, HashMap> files) { - Integer key = getFileListKey(linkageID, isSourceUnit); - List list= files.get(key); - if (list == null) { - list= new LinkedList(); - files.put(key, list); + IIndexFile ifile= null; + if (fResolver.canBePartOfSDK(ifl)) { + // Check for a version in potentially another pdom. + ifile = fIndex.getFile(linkageID, ifl, sigMacros); + } else { + // Search the writable PDOM, only. + IIndexFragmentFile fragFile = fIndex.getWritableFile(linkageID, ifl, sigMacros); + if (fragFile != null && fragFile.hasContent()) { + ifile= fragFile; + } } - list.add(tu); + return ifile == null; + } + + @Override + protected void reportFileWrittenToIndex(FileInAST file, IIndexFragmentFile ifile) { + final FileContentKey fck = file.fFileContentKey; + boolean wasRequested= false; + UpdateKind kind= UpdateKind.OTHER_HEADER; + LinkageTask map = findRequestMap(fck.getLinkageID()); + if (map != null) { + LocationTask locTask = map.find(fck.getLocation()); + if (locTask != null) { + kind= locTask.fKind; + FileVersionTask v = locTask.addVersionTask(ifile); + wasRequested= v.fUpdateRequested; + v.setUpdated(); + } + } + fIndexContentCache.remove(ifile); + reportFile(wasRequested, kind); } - private Integer getFileListKey(int linkageID, boolean isSourceUnit) { - Integer key= new Integer(linkageID * 2 + (isSourceUnit ? 0 : 1)); - return key; + private void store(int linkageID, IIndexFileLocation ifl, HashMap> files) { + List list= files.get(linkageID); + if (list == null) { + list= new LinkedList(); + files.put(linkageID, list); + } + list.add(ifl); } private void removeFilesInIndex(List filesToRemove, List indexFilesToRemove, @@ -661,143 +790,79 @@ public abstract class AbstractIndexerTask extends PDOMWriter { filesToRemove.clear(); } - private void parseFilesUpFront(IProgressMonitor monitor) throws CoreException { - for (String upfront : fFilesUpFront) { - if (monitor.isCanceled()) { - return; - } - String filePath = upfront; - filePath= filePath.trim(); - if (filePath.length() == 0) { - continue; - } - final IPath path= new Path(filePath); - final String fileName = path.lastSegment(); - try { - monitor.subTask(getMessage(MessageKind.parsingFileTask, - fileName, path.removeLastSegments(1).toString())); - - AbstractLanguage[] langs= getLanguages(fileName); - for (AbstractLanguage lang : langs) { - if (fShowActivity) { - trace("Indexer: " + lang.getName() + ": Parsing " + filePath + " up front"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - int linkageID= lang.getLinkageID(); - String code= "#include \"" + filePath + "\"\n"; //$NON-NLS-1$ //$NON-NLS-2$ - - IScannerInfo scanInfo= createDefaultScannerConfig(linkageID); - if (scanInfo != null) { - long start= System.currentTimeMillis(); - IASTTranslationUnit ast= createAST(code, lang, scanInfo, fASTOptions, monitor); - fStatistics.fParsingTime += System.currentTimeMillis() - start; - if (ast != null) { - if (fShowActivity || fShowInclusionProblems) { - IASTNode node= ast.getNodeSelector(null).findEnclosingNode(0,6); - if (node instanceof IASTPreprocessorIncludeStatement) { - IASTPreprocessorIncludeStatement p= (IASTPreprocessorIncludeStatement) node; - String found= p.getPath(); - if (found != null) { - IIndexFileLocation ifl= fResolver.resolveASTPath(found); - IndexFileContent fileinfo = getFileInfo(linkageID, ifl); - if (fileinfo != null) { - if (fileinfo.fIndexFile != null) { - trace(filePath + " was not properly parsed up front for " + lang.getName()); //$NON-NLS-1$ - } - } - } - } - } - writeToIndex(linkageID, ast, StreamHasher.hash(code), computeHashCode(scanInfo), - monitor); - updateFileCount(0, 0, 1); - } - } - } - } catch (Exception e) { - swallowError(path, e); - } catch (Error e) { - swallowError(path, e); - } - } - fFilesUpFront.clear(); - } - - private void parseLinkage(int linkageID, Map> fileListMap, IProgressMonitor monitor) + private void parseLinkage(int linkageID, List files, IProgressMonitor monitor) throws CoreException, InterruptedException { - // Sources - List files= fileListMap.get(getFileListKey(linkageID, true)); - if (files != null) { - for (Iterator iter = files.iterator(); iter.hasNext();) { - Object tu = iter.next(); - if (monitor.isCanceled() || hasUrgentTasks()) - return; - - final IIndexFileLocation ifl = fResolver.resolveFile(tu); - if (ifl != null) { - final IndexFileContent info= getFileInfo(linkageID, ifl); - if (info != null && info.fRequestUpdate && !info.fIsUpdated) { - info.fRequestIsCounted= false; - final IScannerInfo scannerInfo= fResolver.getBuildConfiguration(linkageID, tu); - parseFile(tu, linkageID, ifl, scannerInfo, false, monitor); - if (info.fIsUpdated) { - updateFileCount(1, 0, 0); // a source file was parsed - } - } - } - iter.remove(); + LinkageTask map = findRequestMap(linkageID); + if (map == null || files == null || files.isEmpty()) + return; + + // First parse the required sources + for (Iterator it= files.iterator(); it.hasNext();) { + if (monitor.isCanceled() || hasUrgentTasks()) + return; + IIndexFileLocation ifl= it.next(); + LocationTask locTask = map.find(ifl); + if (locTask == null || locTask.isCompleted()) { + it.remove(); + } else if (locTask.fKind == UpdateKind.REQUIRED_SOURCE) { + final Object tu = locTask.fTu; + final IScannerInfo scannerInfo= fResolver.getBuildConfiguration(linkageID, tu); + parseFile(tu, linkageID, ifl, scannerInfo, false, monitor); + if (locTask.isCompleted()) + it.remove(); } } // Headers with context - HashMap contextMap= new HashMap(); - files= fileListMap.get(getFileListKey(linkageID, false)); - if (files != null) { - for (Iterator iter = files.iterator(); iter.hasNext();) { - if (monitor.isCanceled() || hasUrgentTasks()) - return; - - final Object header= iter.next(); - final IIndexFileLocation ifl = fResolver.resolveFile(header); - final IndexFileContent info= getFileInfo(linkageID, ifl); - if (info != null && info.fRequestUpdate && !info.fIsUpdated) { - if (info.fIndexFile != null && fIndex.isWritableFile(info.fIndexFile)) { - Object tu= findContext(linkageID, (IIndexFragmentFile) info.fIndexFile, contextMap); - if (tu != null) { - final IScannerInfo scannerInfo= fResolver.getBuildConfiguration(linkageID, tu); - info.fRequestIsCounted= false; - parseFile(header, linkageID, ifl, scannerInfo, true, monitor); - if (info.fIsUpdated) { - updateFileCount(0, 1, 1); // a header was parsed in context - iter.remove(); - } - } - } - } else { - // The file has been parsed already. - iter.remove(); - } - } - - // Headers without context - contextMap= null; - for (Iterator iter = files.iterator(); iter.hasNext();) { - if (monitor.isCanceled() || hasUrgentTasks()) - return; - - final Object header= iter.next(); - final IIndexFileLocation ifl = fResolver.resolveFile(header); - final IndexFileContent info= getFileInfo(linkageID, ifl); - if (info != null && info.fRequestUpdate && !info.fIsUpdated) { - info.fRequestIsCounted= false; - final IScannerInfo scannerInfo= fResolver.getBuildConfiguration(linkageID, header); - parseFile(header, linkageID, ifl, scannerInfo, false, monitor); - if (info.fIsUpdated) { - updateFileCount(0, 1, 1); // a header was parsed without context - } - } - iter.remove(); - } - } +// HashMap contextMap= new HashMap(); +// files= files2.get(getFileListKey(linkageID, false)); +// if (files != null) { +// for (Iterator iter = files.iterator(); iter.hasNext();) { +// if (monitor.isCanceled() || hasUrgentTasks()) +// return; +// +// final Object header= iter.next(); +// final IIndexFileLocation ifl = fResolver.resolveFile(header); +// final IndexFileContent info= getFileInfo(linkageID, ifl); +// if (info != null && info.fRequestUpdate && !info.fIsUpdated) { +// if (info.fIndexFile != null && fIndex.isWritableFile(info.fIndexFile)) { +// Object tu= findContext(linkageID, (IIndexFragmentFile) info.fIndexFile, contextMap); +// if (tu != null) { +// final IScannerInfo scannerInfo= fResolver.getBuildConfiguration(linkageID, tu); +// info.fRequestIsCounted= false; +// parseFile(header, linkageID, ifl, scannerInfo, true, monitor); +// if (info.fIsUpdated) { +// updateFileCount(0, 1, 1); // a header was parsed in context +// iter.remove(); +// } +// } +// } +// } else { +// // The file has been parsed already. +// iter.remove(); +// } +// } +// +// // Headers without context +// contextMap= null; +// for (Iterator iter = files.iterator(); iter.hasNext();) { +// if (monitor.isCanceled() || hasUrgentTasks()) +// return; +// +// final Object header= iter.next(); +// final IIndexFileLocation ifl = fResolver.resolveFile(header); +// final IndexFileContent info= getFileInfo(linkageID, ifl); +// if (info != null && info.fRequestUpdate && !info.fIsUpdated) { +// info.fRequestIsCounted= false; +// final IScannerInfo scannerInfo= fResolver.getBuildConfiguration(linkageID, header); +// parseFile(header, linkageID, ifl, scannerInfo, false, monitor); +// if (info.fIsUpdated) { +// updateFileCount(0, 1, 1); // a header was parsed without context +// } +// } +// iter.remove(); +// } +// } } private synchronized boolean hasUrgentTasks() { @@ -815,35 +880,36 @@ public abstract class AbstractIndexerTask extends PDOMWriter { private static final Object NO_CONTEXT= new Object(); private Object findContext(int linkageID, IIndexFragmentFile ifile, HashMap contextMap) { - Object cachedContext= contextMap.get(ifile); - if (cachedContext != null) { - return cachedContext == NO_CONTEXT ? null : cachedContext; - } - try { - Object context= fResolver.getInputFile(ifile.getLocation()); - if (context != null && fResolver.isSourceUnit(context)) { - contextMap.put(ifile, context); - return context; - } - - contextMap.put(ifile, NO_CONTEXT); // prevent recursion - final IIndexInclude contextInclude= ifile.getParsedInContext(); - if (contextInclude != null) { - // in case we are in context of another file that will be indexed, just wait. - final IndexFileContent info= getFileInfo(linkageID, contextInclude.getIncludedByLocation()); - if (info != null && info.fRequestUpdate) { - return null; - } - final IIndexFragmentFile contextIFile= (IIndexFragmentFile) contextInclude.getIncludedBy(); - context= findContext(linkageID, contextIFile, contextMap); - if (context != null) { - contextMap.put(ifile, context); - return context; - } - } - } catch (CoreException e) { - CCorePlugin.log(e); - } + // mstodo +// Object cachedContext= contextMap.get(ifile); +// if (cachedContext != null) { +// return cachedContext == NO_CONTEXT ? null : cachedContext; +// } +// try { +// Object context= fResolver.getInputFile(ifile.getLocation()); +// if (context != null && fResolver.isSourceUnit(context)) { +// contextMap.put(ifile, context); +// return context; +// } +// +// contextMap.put(ifile, NO_CONTEXT); // prevent recursion +// final IIndexInclude contextInclude= ifile.getParsedInContext(); +// if (contextInclude != null) { +// // in case we are in context of another file that will be indexed, just wait. +// final IndexFileContent info= getFileInfo(linkageID, contextInclude.getIncludedByLocation()); +// if (info != null && info.fUpdateRequested) { +// return null; +// } +// final IIndexFragmentFile contextIFile= (IIndexFragmentFile) contextInclude.getIncludedBy(); +// context= findContext(linkageID, contextIFile, contextMap); +// if (context != null) { +// contextMap.put(ifile, context); +// return context; +// } +// } +// } catch (CoreException e) { +// CCorePlugin.log(e); +// } return null; } @@ -874,7 +940,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { IASTTranslationUnit ast= createAST(tu, lang, codeReader, scanInfo, fASTOptions, inContext, pm); fStatistics.fParsingTime += System.currentTimeMillis() - start; if (ast != null) { - writeToIndex(linkageID, ast, codeReader.getContentsHash(), computeHashCode(scanInfo), pm); + writeToIndex(linkageID, ast, codeReader.getContentsHash(), pm); } } catch (CoreException e) { th= e; @@ -894,77 +960,77 @@ public abstract class AbstractIndexerTask extends PDOMWriter { } } - private void writeToIndex(final int linkageID, IASTTranslationUnit ast, long fileContentsHash, - int configHash, IProgressMonitor pm) throws CoreException, InterruptedException { - HashSet enteredFiles= new HashSet(); - ArrayList orderedIFLs= new ArrayList(); + private void writeToIndex(final int linkageID, IASTTranslationUnit ast, long fileContentsHash, IProgressMonitor pm) + throws CoreException, InterruptedException { + HashSet enteredFiles= new HashSet(); + ArrayList orderedFileKeys= new ArrayList(); final IIndexFileLocation topIfl = fResolver.resolveASTPath(ast.getFilePath()); - enteredFiles.add(topIfl); + FileContentKey topKey = new FileContentKey(linkageID, topIfl, ast.getSignificantMacros()); + enteredFiles.add(topKey); IDependencyTree tree= ast.getDependencyTree(); IASTInclusionNode[] inclusions= tree.getInclusions(); for (IASTInclusionNode inclusion : inclusions) { - collectOrderedIFLs(linkageID, inclusion, enteredFiles, orderedIFLs); + collectOrderedFileKeys(linkageID, inclusion, enteredFiles, orderedFileKeys); } - IndexFileContent info= getFileInfo(linkageID, topIfl); - if (info != null && info.fRequestUpdate && !info.fIsUpdated) { - orderedIFLs.add(topIfl); + if (needToStoreInIndex(linkageID, topIfl, ast.getSignificantMacros())) { + orderedFileKeys.add(new FileInAST(null, topKey)); } - IIndexFileLocation[] ifls= orderedIFLs.toArray(new IIndexFileLocation[orderedIFLs.size()]); + FileInAST[] fileKeys= orderedFileKeys.toArray(new FileInAST[orderedFileKeys.size()]); try { - addSymbols(ast, ifls, fIndex, 1, false, fileContentsHash, configHash, fTodoTaskUpdater, pm); - } finally { - // mark as updated in any case, to avoid parsing files that caused an exception to be thrown. - for (IIndexFileLocation ifl : ifls) { - info= getFileInfo(linkageID, ifl); - Assert.isNotNull(info); - info.fIsUpdated= true; - } + addSymbols(ast, fileKeys, fIndex, 1, false, fileContentsHash, fTodoTaskUpdater, pm); + } catch (CoreException e) { + // Avoid parsing files again, that caused an exception to be thrown. + withdrawRequests(linkageID, fileKeys); + throw e; + } catch (RuntimeException e) { + withdrawRequests(linkageID, fileKeys); + throw e; + } catch (Error e) { + withdrawRequests(linkageID, fileKeys); + throw e; } } - private void collectOrderedIFLs(final int linkageID, IASTInclusionNode inclusion, - HashSet enteredFiles, ArrayList orderedIFLs) throws CoreException { - final IASTPreprocessorIncludeStatement id= inclusion.getIncludeDirective(); - if (id.isActive() && id.isResolved()) { - final IIndexFileLocation ifl= fResolver.resolveASTPath(id.getPath()); - final boolean isFirstEntry= enteredFiles.add(ifl); - IASTInclusionNode[] nested= inclusion.getNestedInclusions(); - for (IASTInclusionNode element : nested) { - collectOrderedIFLs(linkageID, element, enteredFiles, orderedIFLs); - } - if (isFirstEntry && needToUpdateHeader(linkageID, ifl)) { - orderedIFLs.add(ifl); - } - } - } - - public final boolean needToUpdateHeader(int linkageID, IIndexFileLocation ifl) throws CoreException { - IndexFileContent info= getFileInfo(linkageID, ifl); - if (info == null) { - IIndexFile ifile= null; - if (fResolver.canBePartOfSDK(ifl)) { - ifile= fIndex.getFile(linkageID, ifl); - } else { - IIndexFragmentFile fragFile= fIndex.getWritableFile(linkageID, ifl); - if (fragFile != null && fragFile.hasContent()) { - ifile= fragFile; + public void withdrawRequests(int linkageID, FileInAST[] fileKeys) { + LinkageTask map = findRequestMap(linkageID); + if (map != null) { + for (FileInAST fileKey : fileKeys) { + LocationTask locTask = map.find(fileKey.fFileContentKey.getLocation()); + if (locTask != null) { + if (locTask.fAddRequested) { + locTask.fAddRequested= false; + reportFile(true, locTask.fKind); + } else { + for (FileVersionTask fc : locTask.fIndexFiles) { + if (fc.fUpdateRequested) { + reportFile(true, locTask.fKind); + fc.setUpdated(); + } + } + } } } - info= createFileInfo(new FileKey(linkageID, ifl.getURI()), ifile); - if (ifile == null) { - info.fRequestIsCounted= false; - info.fRequestUpdate= true; + } + } + + private void collectOrderedFileKeys(final int linkageID, IASTInclusionNode inclusion, + HashSet enteredFiles, ArrayList orderedFileKeys) throws CoreException { + final IASTPreprocessorIncludeStatement include= inclusion.getIncludeDirective(); + if (include.isActive() && include.isResolved()) { + final IIndexFileLocation ifl= fResolver.resolveASTPath(include.getPath()); + FileContentKey fileKey = new FileContentKey(linkageID, ifl, include.getSignificantMacros()); + final boolean isFirstEntry= enteredFiles.add(fileKey); + IASTInclusionNode[] nested= inclusion.getNestedInclusions(); + for (IASTInclusionNode element : nested) { + collectOrderedFileKeys(linkageID, element, enteredFiles, orderedFileKeys); + } + if (isFirstEntry && needToStoreInIndex(linkageID, ifl, include.getSignificantMacros())) { + orderedFileKeys.add(new FileInAST(include, fileKey)); } } - final boolean needUpdate= !info.fIsUpdated && info.fRequestUpdate; - if (needUpdate && info.fRequestIsCounted) { - updateFileCount(0, 1, 0); // total headers will be counted when written to db - info.fRequestIsCounted= false; - } - return needUpdate; } private IPath getPathForLabel(IIndexFileLocation ifl) { @@ -1030,74 +1096,46 @@ public abstract class AbstractIndexerTask extends PDOMWriter { CCorePlugin.log(e); } - private static int computeHashCode(IScannerInfo scannerInfo) { - int result= 0; - Map macros= scannerInfo.getDefinedSymbols(); - if (macros != null) { - for (Entry entry : macros.entrySet()) { - String key = entry.getKey(); - String value = entry.getValue(); - result= addToHashcode(result, key); - if (value != null && value.length() > 0) { - result= addToHashcode(result, value); - } - } - } - String[] a= scannerInfo.getIncludePaths(); - if (a != null) { - for (String element : a) { - result= addToHashcode(result, element); - - } - } - if (scannerInfo instanceof IExtendedScannerInfo) { - IExtendedScannerInfo esi= (IExtendedScannerInfo) scannerInfo; - a= esi.getIncludeFiles(); - if (a != null) { - for (String element : a) { - result= addToHashcode(result, element); - - } - } - a= esi.getLocalIncludePath(); - if (a != null) { - for (String element : a) { - result= addToHashcode(result, element); - } - } - a= esi.getMacroFiles(); - if (a != null) { - for (String element : a) { - result= addToHashcode(result, element); - } - } - } - return result; - } - - private static int addToHashcode(int result, String key) { - return result * 31 + key.hashCode(); - } - private long computeFileContentsHash(Object tu) { FileContent codeReader= fResolver.getCodeReader(tu); return codeReader != null ? codeReader.getContentsHash() : 0; } - public final IndexFileContent getFileContent(int linkageID, IIndexFileLocation ifl) throws CoreException { - if (!needToUpdateHeader(linkageID, ifl)) { - IndexFileContent info= getFileInfo(linkageID, ifl); - Assert.isNotNull(info); - if (info.fIndexFile == null) { - info.fIndexFile= fIndex.getFile(linkageID, ifl); - if (info.fIndexFile == null) { + public final IndexFileContent getFileContent(int linkageID, IIndexFileLocation ifl, + IIndexFile file) throws CoreException { + LinkageTask map = findRequestMap(linkageID); + if (map != null) { + LocationTask request= map.find(ifl); + if (request != null) { + FileVersionTask task= request.findVersion(file); + if (task != null && task.fUpdateRequested) return null; - } } - return info; + } + IndexFileContent fc= fIndexContentCache.get(file); + if (fc == null) { + fc= new IndexFileContent(file); + fIndexContentCache.put(file, fc); + } + return fc; + } + + public IIndexFile selectIndexFile(int linkageID, IIndexFileLocation ifl, IMacroDictionary md) throws CoreException { + LinkageTask map = findRequestMap(linkageID); + if (map != null) { + LocationTask request= map.find(ifl); + if (request == null) { + request= map.cacheIndexFiles(ifl, fIndex.getFiles(linkageID, ifl)); + } + for (FileVersionTask fileVersion : request.fIndexFiles) { + final IIndexFile indexFile = fileVersion.fIndexFile; + if (!fileVersion.fUpdateRequested && md.satisfies(indexFile.getSignificantMacros())) + return indexFile; + } } return null; } + protected String getMessage(MessageKind kind, Object... arguments) { switch (kind) { @@ -1117,4 +1155,4 @@ public abstract class AbstractIndexerTask extends PDOMWriter { protected int[] getLinkagesToParse() { return PDOMManager.IDS_FOR_LINKAGES_TO_INDEX; } -} \ No newline at end of file +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java index 0c1d82decf1..019c75bc4c6 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java @@ -56,6 +56,7 @@ import org.eclipse.cdt.core.index.IIndexLocationConverter; import org.eclipse.cdt.core.index.IIndexMacro; import org.eclipse.cdt.core.index.IIndexMacroContainer; import org.eclipse.cdt.core.index.IndexFilter; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.internal.core.dom.Linkage; @@ -210,10 +211,11 @@ public class PDOM extends PlatformObject implements IPDOM { * CDT 8.1 development (versions not supported on teh 8.0.x branch) * 120.0 - Enumerators in global index, bug 356235 * 120.1 - Specializations of using declarations, bug 357293. + * 121.0 - Multiple variants of included header file, bug 197989. */ - private static final int MIN_SUPPORTED_VERSION= version(120, 0); - private static final int MAX_SUPPORTED_VERSION= version(120, Short.MAX_VALUE); - private static final int DEFAULT_VERSION = version(120, 1); + private static final int MIN_SUPPORTED_VERSION= version(121, 0); + private static final int MAX_SUPPORTED_VERSION= version(121, Short.MAX_VALUE); + private static final int DEFAULT_VERSION = version(121, 0); private static int version(int major, int minor) { return (major << 16) + minor; @@ -419,6 +421,7 @@ public class PDOM extends PlatformObject implements IPDOM { return fileIndex; } + @Deprecated public PDOMFile getFile(int linkageID, IIndexFileLocation location) throws CoreException { PDOMLinkage linkage= getLinkage(linkageID); if (linkage == null) @@ -426,8 +429,25 @@ public class PDOM extends PlatformObject implements IPDOM { return PDOMFile.findFile(linkage, getFileIndex(), location, locationConverter); } - public PDOMFile getFile(PDOMLinkage linkage, IIndexFileLocation location) throws CoreException { - return PDOMFile.findFile(linkage, getFileIndex(), location, locationConverter); + public PDOMFile getFile(int linkageID, IIndexFileLocation location, + ISignificantMacros macroDictionary) throws CoreException { + PDOMLinkage linkage= getLinkage(linkageID); + if (linkage == null) + return null; + return PDOMFile.findFile(linkage, getFileIndex(), location, locationConverter, + macroDictionary); + } + + public PDOMFile getFile(PDOMLinkage linkage, IIndexFileLocation location, + ISignificantMacros macroDictionary) throws CoreException { + return PDOMFile.findFile(linkage, getFileIndex(), location, locationConverter, macroDictionary); + } + + public IIndexFragmentFile[] getFiles(int linkageID, IIndexFileLocation location) throws CoreException { + PDOMLinkage linkage= getLinkage(linkageID); + if (linkage == null) + return IIndexFragmentFile.EMPTY_ARRAY; + return PDOMFile.findFiles(linkage, getFileIndex(), location, locationConverter); } public IIndexFragmentFile[] getFiles(IIndexFileLocation location) throws CoreException { @@ -436,7 +456,7 @@ public class PDOM extends PlatformObject implements IPDOM { public IIndexFragmentFile[] getAllFiles() throws CoreException { final List locations = new ArrayList(); - getFileIndex().accept(new IBTreeVisitor(){ + getFileIndex().accept(new IBTreeVisitor() { public int compare(long record) throws CoreException { return 0; } @@ -449,11 +469,12 @@ public class PDOM extends PlatformObject implements IPDOM { return locations.toArray(new IIndexFragmentFile[locations.size()]); } - protected IIndexFragmentFile addFile(int linkageID, IIndexFileLocation location) throws CoreException { + protected IIndexFragmentFile addFile(int linkageID, IIndexFileLocation location, + ISignificantMacros sigMacros) throws CoreException { PDOMLinkage linkage= createLinkage(linkageID); - IIndexFragmentFile file = getFile(linkage, location); + IIndexFragmentFile file = getFile(linkage, location, sigMacros); if (file == null) { - PDOMFile pdomFile = new PDOMFile(linkage, location, linkageID); + PDOMFile pdomFile = new PDOMFile(linkage, location, linkageID, sigMacros); getFileIndex().insert(pdomFile.getRecord()); file= pdomFile; fEvent.setHasNewFiles(); @@ -1077,7 +1098,7 @@ public class PDOM extends PlatformObject implements IPDOM { return (PDOMFile) file; } - return getFile(file.getLinkageID(), file.getLocation()); + return getFile(file.getLinkageID(), file.getLocation(), file.getSignificantMacros()); } public File getPath() { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMFileSet.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMFileSet.java index bf00566c876..fa836eda9fb 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMFileSet.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMFileSet.java @@ -28,6 +28,11 @@ public class PDOMFileSet implements IIndexFragmentFileSet { fFileIDs.add(pdomFile.getRecord()); } + public void remove(IIndexFragmentFile fragFile) { + PDOMFile pdomFile= (PDOMFile) fragFile; + fFileIDs.remove(pdomFile.getRecord()); + } + public boolean containsFileOfLocalBinding(IIndexFragmentBinding fb) throws CoreException { PDOMBinding pdomBinding= (PDOMBinding) fb; return fFileIDs.contains(pdomBinding.getLocalToFileRec()); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMProxy.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMProxy.java index f7684b13de8..0604bc2e191 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMProxy.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMProxy.java @@ -24,6 +24,7 @@ import org.eclipse.cdt.core.index.IIndexFileLocation; import org.eclipse.cdt.core.index.IIndexLinkage; import org.eclipse.cdt.core.index.IIndexMacro; import org.eclipse.cdt.core.index.IndexFilter; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.internal.core.index.IIndexFragmentBinding; import org.eclipse.cdt.internal.core.index.IIndexFragmentFile; import org.eclipse.cdt.internal.core.index.IIndexFragmentFileSet; @@ -53,6 +54,7 @@ public class PDOMProxy implements IPDOM { fLockDebugging= new HashMap(); } } + public synchronized void acquireReadLock() throws InterruptedException { if (fDelegate != null) { fDelegate.acquireReadLock(); @@ -152,6 +154,7 @@ public class PDOMProxy implements IPDOM { return 0; } + @Deprecated public synchronized IIndexFragmentFile getFile(int linkageID, IIndexFileLocation location) throws CoreException { if (fDelegate != null) return fDelegate.getFile(linkageID, location); @@ -159,6 +162,22 @@ public class PDOMProxy implements IPDOM { return null; } + public IIndexFragmentFile getFile(int linkageID, IIndexFileLocation location, + ISignificantMacros sigMacros) throws CoreException { + if (fDelegate != null) + return fDelegate.getFile(linkageID, location, sigMacros); + + return null; + } + + public IIndexFragmentFile[] getFiles(int linkageID, IIndexFileLocation location) + throws CoreException { + if (fDelegate != null) + return fDelegate.getFiles(linkageID, location); + + return IIndexFragmentFile.EMPTY_ARRAY; + } + public synchronized IIndexFragmentFile[] getFiles(IIndexFileLocation location) throws CoreException { if (fDelegate != null) return fDelegate.getFiles(location); @@ -289,10 +308,12 @@ public class PDOMProxy implements IPDOM { public Object putCachedResult(Object key, Object value, boolean replace) { return value; } + public void clearResultCache() { if (fDelegate != null) fDelegate.clearResultCache(); } + /* (non-Javadoc) * @see org.eclipse.cdt.internal.core.index.IIndexFragment#getInlineNamespaces() */ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMWriter.java index b435461ca37..6b1870b07d3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMWriter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMWriter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2011 Wind River Systems, Inc. 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 @@ -13,7 +13,6 @@ package org.eclipse.cdt.internal.core.pdom; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -50,8 +49,10 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; import org.eclipse.cdt.core.index.IIndexFileLocation; import org.eclipse.cdt.core.index.IIndexInclude; import org.eclipse.cdt.core.parser.IProblem; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; +import org.eclipse.cdt.internal.core.index.FileContentKey; import org.eclipse.cdt.internal.core.index.IIndexFragmentFile; import org.eclipse.cdt.internal.core.index.IWritableIndex; import org.eclipse.cdt.internal.core.index.IWritableIndex.IncludeInformation; @@ -70,6 +71,20 @@ import org.eclipse.osgi.util.NLS; * @since 4.0 */ abstract public class PDOMWriter { + public static class FileInAST { + public FileInAST(IASTPreprocessorIncludeStatement includeStmt, FileContentKey key) { + fIncludeStatement= includeStmt; + fFileContentKey= key; + } + final IASTPreprocessorIncludeStatement fIncludeStatement; + final FileContentKey fFileContentKey; + + @Override + public String toString() { + return fFileContentKey.toString(); + } + } + public static int SKIP_ALL_REFERENCES= -1; public static int SKIP_TYPE_REFERENCES= 1; public static int SKIP_MACRO_REFERENCES= 2; @@ -77,9 +92,24 @@ abstract public class PDOMWriter { public static int SKIP_NO_REFERENCES= 0; private static class Symbols { - ArrayList fNames= new ArrayList(); - ArrayList fMacros= new ArrayList(); - ArrayList fIncludes= new ArrayList(); + final ArrayList fNames= new ArrayList(); + final ArrayList fMacros= new ArrayList(); + final ArrayList fIncludes= new ArrayList(); + } + + private static class Data { + final IASTTranslationUnit fAST; + final FileInAST[] fSelectedFiles; + final IWritableIndex fIndex; + final Map fSymbolMap = new HashMap(); + final Set fContextIncludes = new HashSet(); + final List fStati= new ArrayList(); + + public Data(IASTTranslationUnit ast, FileInAST[] selectedFiles, IWritableIndex index) { + fAST= ast; + fSelectedFiles= selectedFiles; + fIndex= index; + } } private boolean fShowProblems; @@ -90,7 +120,6 @@ abstract public class PDOMWriter { protected final IndexerStatistics fStatistics; protected final IndexerInputAdapter fResolver; - private IndexerProgress fInfo= new IndexerProgress(); private int fSkipReferences= SKIP_NO_REFERENCES; public PDOMWriter(IndexerInputAdapter resolver) { @@ -140,39 +169,44 @@ abstract public class PDOMWriter { * * When flushIndex is set to false, you must make sure to flush * the index after your last write operation. - * @since 4.0 */ - public void addSymbols(IASTTranslationUnit ast, IIndexFileLocation[] ifls, IWritableIndex index, - int readlockCount, boolean flushIndex, long fileContentsHash, int configHash, + public void addSymbols(IASTTranslationUnit ast, FileInAST[] selectedFiles, IWritableIndex index, + int readlockCount, boolean flushIndex, long fileContentsHash, ITodoTaskUpdater taskUpdater, IProgressMonitor pm) throws InterruptedException, CoreException { if (fShowProblems) { fShowInclusionProblems= true; fShowScannerProblems= true; fShowSyntaxProblems= true; } - final Map symbolMap= new HashMap(); - for (IIndexFileLocation ifl : ifls) { - prepareInMap(symbolMap, ifl); + + Data info= new Data(ast, selectedFiles, index); + for (FileInAST file : selectedFiles) { + info.fSymbolMap.put(file.fIncludeStatement, new Symbols()); } - ArrayList stati= new ArrayList(); + - HashSet contextIncludes= new HashSet(); - extractSymbols(ast, symbolMap, contextIncludes); + // Extract symbols from AST + extractSymbols(info); - // name resolution - resolveNames(symbolMap, ifls, stati, pm); + // Name resolution + resolveNames(info, pm); - // index update - storeSymbolsInIndex(symbolMap, ifls, ast.getLinkage().getLinkageID(), fileContentsHash, - configHash, contextIncludes, index, readlockCount, flushIndex, stati, pm); + // Index update + storeSymbolsInIndex(info, fileContentsHash, readlockCount, flushIndex, pm); + // Tasks update if (taskUpdater != null) { - taskUpdater.updateTasks(ast.getComments(), ifls); + Set locations= new HashSet(); + for (FileInAST file : selectedFiles) { + locations.add(file.fFileContentKey.getLocation()); + } + taskUpdater.updateTasks(ast.getComments(), locations.toArray(new IIndexFileLocation[locations.size()])); } - if (!stati.isEmpty()) { + if (!info.fStati.isEmpty()) { + List stati = info.fStati; String path= null; - if (ifls.length > 0) { - path= ifls[ifls.length - 1].getURI().getPath(); + if (selectedFiles.length > 0) { + path= selectedFiles[selectedFiles.length - 1].fFileContentKey.getLocation().getURI().getPath(); } else { path= ast.getFilePath().toString(); } @@ -190,26 +224,24 @@ abstract public class PDOMWriter { } } - private void storeSymbolsInIndex(final Map symbolMap, IIndexFileLocation[] ifls, - int linkageID, long fileContentsHash, int configHash, - HashSet contextIncludes, IWritableIndex index, int readlockCount, - boolean flushIndex, ArrayList stati, IProgressMonitor pm) - throws InterruptedException, CoreException { - for (int i= 0; i < ifls.length; i++) { + private void storeSymbolsInIndex(final Data data, long fileContentsHash, int readlockCount, + boolean flushIndex, IProgressMonitor pm) throws InterruptedException, CoreException { + final int linkageID= data.fAST.getLinkage().getLinkageID(); + for (int i= 0; i < data.fSelectedFiles.length; i++) { if (pm.isCanceled()) return; - final IIndexFileLocation ifl= ifls[i]; - if (ifl != null) { + final FileInAST file= data.fSelectedFiles[i]; + if (file != null) { if (fShowActivity) { - trace("Indexer: adding " + ifl.getURI()); //$NON-NLS-1$ + trace("Indexer: adding " + file.fFileContentKey.getLocation().getURI()); //$NON-NLS-1$ } Throwable th= null; - YieldableIndexLock lock = new YieldableIndexLock(index, readlockCount, flushIndex); + YieldableIndexLock lock = new YieldableIndexLock(data.fIndex, readlockCount, flushIndex); lock.acquire(); try { - storeFileInIndex(index, ifl, symbolMap, linkageID, fileContentsHash, configHash, - contextIncludes, lock); + IIndexFragmentFile ifile= storeFileInIndex(data, file, linkageID, fileContentsHash, lock); + reportFileWrittenToIndex(file, ifile); } catch (RuntimeException e) { th= e; } catch (StackOverflowError e) { @@ -219,31 +251,27 @@ abstract public class PDOMWriter { } finally { // When the caller holds a read-lock, the result cache of the index is never cleared. // ==> Before releasing the lock for the last time in this ast, we clear the result cache. - if (readlockCount > 0 && i == ifls.length-1) { - index.clearResultCache(); + if (readlockCount > 0 && i == data.fSelectedFiles.length-1) { + data.fIndex.clearResultCache(); } lock.release(); } if (th != null) { - stati.add(createStatus(NLS.bind(Messages.PDOMWriter_errorWhileParsing, - ifl.getURI().getPath()), th)); - } - if (i < ifls.length - 1) { - updateFileCount(0, 0, 1); // update header count + data.fStati.add(createStatus(NLS.bind(Messages.PDOMWriter_errorWhileParsing, + file.fFileContentKey.getLocation().getURI().getPath()), th)); } fStatistics.fAddToIndexTime += lock.getCumulativeLockTime(); } } } - private void resolveNames(final Map symbolMap, IIndexFileLocation[] ifls, - ArrayList stati, IProgressMonitor pm) { + private void resolveNames(Data data, IProgressMonitor pm) { long start= System.currentTimeMillis(); - for (IIndexFileLocation path : ifls) { + for (FileInAST file : data.fSelectedFiles) { if (pm.isCanceled()) { return; } - Symbols symbols= symbolMap.get(path); + Symbols symbols= data.fSymbolMap.get(file.fIncludeStatement); final ArrayList names= symbols.fNames; boolean reported= false; @@ -286,8 +314,8 @@ abstract public class PDOMWriter { } if (th != null) { if (!reported) { - stati.add(CCorePlugin.createStatus(NLS.bind(Messages.PDOMWriter_errorResolvingName, - name.toString(), path.getURI().getPath()), th)); + data.fStati.add(CCorePlugin.createStatus(NLS.bind(Messages.PDOMWriter_errorResolvingName, + name.toString(), file.fFileContentKey.getLocation().getURI().getPath()), th)); } reported= true; j.remove(); @@ -298,45 +326,44 @@ abstract public class PDOMWriter { fStatistics.fResolutionTime += System.currentTimeMillis()-start; } - private void extractSymbols(IASTTranslationUnit ast, final Map symbolMap, - Collection contextIncludes) throws CoreException { - final HashSet contextIFLs= new HashSet(); - final IIndexFileLocation astIFL = fResolver.resolveASTPath(ast.getFilePath()); - + private void extractSymbols(Data data) throws CoreException { int unresolvedIncludes= 0; + final IASTTranslationUnit ast = data.fAST; + final Map symbolMap = data.fSymbolMap; + IASTPreprocessorStatement[] stmts = ast.getAllPreprocessorStatements(); for (final IASTPreprocessorStatement stmt : stmts) { - // includes + // Includes. if (stmt instanceof IASTPreprocessorIncludeStatement) { IASTPreprocessorIncludeStatement include= (IASTPreprocessorIncludeStatement) stmt; final IASTFileLocation astLoc= include.getFileLocation(); - final IIndexFileLocation sourceIFL= astLoc != null ? fResolver.resolveASTPath(astLoc.getFileName()) : astIFL; // command-line includes - final boolean updateSource= symbolMap.containsKey(sourceIFL); + IASTPreprocessorIncludeStatement owner = astLoc.getContextInclusionStatement(); + final boolean updateSource= symbolMap.containsKey(owner); if (updateSource) { - addToMap(symbolMap, sourceIFL, include); + addToMap(symbolMap, owner, include); } if (include.isActive()) { if (!include.isResolved()) { unresolvedIncludes++; } else if (updateSource) { - // the include was parsed, check if we want to update the included file in the index - final IIndexFileLocation targetIFL= fResolver.resolveASTPath(include.getPath()); - if (symbolMap.containsKey(targetIFL) && contextIFLs.add(targetIFL)) { - contextIncludes.add(include); + // The include was parsed, check if we want to update the included file in the index. + if (symbolMap.containsKey(include)) { + data.fContextIncludes.add(include); } } } - } else if (stmt.isActive() && (stmt instanceof IASTPreprocessorUndefStatement || stmt instanceof IASTPreprocessorMacroDefinition)) { + } else if (stmt.isActive() && + (stmt instanceof IASTPreprocessorUndefStatement || stmt instanceof IASTPreprocessorMacroDefinition)) { IASTFileLocation sourceLoc = stmt.getFileLocation(); if (sourceLoc != null) { // skip built-ins and command line macros - IIndexFileLocation path2 = fResolver.resolveASTPath(sourceLoc.getFileName()); - addToMap(symbolMap, path2, stmt); + IASTPreprocessorIncludeStatement owner = sourceLoc.getContextInclusionStatement(); + addToMap(symbolMap, owner, stmt); } } } - // names + // Names. final IndexerASTVisitor visitor = new IndexerASTVisitor((fSkipReferences & SKIP_IMPLICIT_REFERENCES) == 0) { @Override public void visit(IASTName name, IASTName caller) { @@ -348,13 +375,13 @@ abstract public class PDOMWriter { } } - // assign a location to anonymous types. + // Assign a location to anonymous types. name= PDOMASTAdapter.getAdapterIfAnonymous(name); if (name != null) { IASTFileLocation nameLoc = name.getFileLocation(); if (nameLoc != null) { - IIndexFileLocation location = fResolver.resolveASTPath(nameLoc.getFileName()); - addToMap(symbolMap, location, new IASTName[]{name, caller}); + IASTPreprocessorIncludeStatement owner= nameLoc.getContextInclusionStatement(); + addToMap(symbolMap, owner, new IASTName[] { name, caller }); } } } @@ -368,8 +395,8 @@ abstract public class PDOMWriter { for (IASTName name : refs) { IASTFileLocation nameLoc = name.getFileLocation(); if (nameLoc != null) { - IIndexFileLocation location = fResolver.resolveASTPath(nameLoc.getFileName()); - addToMap(symbolMap, location, new IASTName[]{name, null}); + IASTPreprocessorIncludeStatement owner= nameLoc.getContextInclusionStatement(); + addToMap(symbolMap, owner, new IASTName[] { name, null }); } } } @@ -426,44 +453,41 @@ abstract public class PDOMWriter { return false; } - private void addToMap(Map map, IIndexFileLocation location, IASTName[] thing) { - Symbols lists= map.get(location); + private void addToMap(Map symbolMap, IASTPreprocessorIncludeStatement owner, IASTName[] thing) { + Symbols lists= symbolMap.get(owner); if (lists != null) lists.fNames.add(thing); } - private void addToMap(Map map, IIndexFileLocation location, - IASTPreprocessorIncludeStatement thing) { - Symbols lists= map.get(location); + private void addToMap(Map symbolMap, IASTPreprocessorIncludeStatement owner, IASTPreprocessorIncludeStatement thing) { + Symbols lists= symbolMap.get(owner); if (lists != null) lists.fIncludes.add(thing); } - private void addToMap(Map map, IIndexFileLocation location, - IASTPreprocessorStatement thing) { - Symbols lists= map.get(location); + private void addToMap(Map symbolMap, + IASTPreprocessorIncludeStatement owner, IASTPreprocessorStatement thing) { + Symbols lists= symbolMap.get(owner); if (lists != null) lists.fMacros.add(thing); } - private boolean prepareInMap(Map map, IIndexFileLocation location) { - if (map.get(location) == null) { - map.put(location, new Symbols()); - } - return false; - } - - private IIndexFragmentFile storeFileInIndex(IWritableIndex index, IIndexFileLocation location, - Map symbolMap, int linkageID, long fileContentsHash, - int configHash, Set contextIncludes, - YieldableIndexLock lock) throws CoreException, InterruptedException { + private IIndexFragmentFile storeFileInIndex(Data data, FileInAST astFile, int linkageID, + long fileContentsHash, YieldableIndexLock lock) throws CoreException, + InterruptedException { + final IWritableIndex index = data.fIndex; Set clearedContexts= Collections.emptySet(); IIndexFragmentFile file; - // We create a temporary PDOMFile with zero timestamp, add names to it, then replace contents - // of the old file from the temporary one, then delete the temporary file. The write lock on - // the index can be yielded between adding names to the temporary file, if another thread - // is waiting for a read lock. - IIndexFragmentFile oldFile = index.getWritableFile(linkageID, location); + // We create a temporary PDOMFile with zero timestamp, add names to it, then replace + // contents of the old file from the temporary one, then delete the temporary file. + // The write lock on the index can be yielded between adding names to the temporary file, + // if another thread is waiting for a read lock. + final FileContentKey fileKey = astFile.fFileContentKey; + final IASTPreprocessorIncludeStatement owner= astFile.fIncludeStatement; + + IIndexFileLocation location = fileKey.getLocation(); + ISignificantMacros significantMacros = fileKey.getSignificantMacros(); + IIndexFragmentFile oldFile = index.getWritableFile(linkageID, location, significantMacros); if (oldFile != null) { IIndexInclude[] includedBy = index.findIncludedBy(oldFile); if (includedBy.length > 0) { @@ -473,10 +497,12 @@ abstract public class PDOMWriter { } } } - file= index.addUncommittedFile(linkageID, location); + file= index.addUncommittedFile(linkageID, location, significantMacros); try { - file.setScannerConfigurationHashcode(configHash); - Symbols lists= symbolMap.get(location); + boolean pragmaOnce= owner != null ? owner.hasPragmaOnceSemantics() : data.fAST.hasPragmaOnceSemantics(); + file.setPragmaOnceSemantics(pragmaOnce); + + Symbols lists= data.fSymbolMap.get(owner); if (lists != null) { IASTPreprocessorStatement[] macros= lists.fMacros.toArray(new IASTPreprocessorStatement[lists.fMacros.size()]); IASTName[][] names= lists.fNames.toArray(new IASTName[lists.fNames.size()][]); @@ -495,7 +521,7 @@ abstract public class PDOMWriter { if (include.isResolved()) { info.fLocation= fResolver.resolveASTPath(include.getPath()); info.fIsContext= include.isActive() && - (contextIncludes.contains(include) || clearedContexts.contains(info.fLocation)); + (data.fContextIncludes.contains(include) || clearedContexts.contains(info.fLocation)); } } index.setFileContent(file, linkageID, includeInfos, macros, names, fResolver, lock); @@ -511,34 +537,9 @@ abstract public class PDOMWriter { } /** - * Makes a copy of the current progress information and returns it. - * @since 4.0 + * Informs the subclass that a file has been stored in the index. */ - public IndexerProgress getProgressInformation() { - synchronized (fInfo) { - return new IndexerProgress(fInfo); - } - } - - /** - * Updates current progress information with the provided delta. - */ - protected final void updateFileCount(int sources, int primaryHeader, int header) { - synchronized (fInfo) { - fInfo.fCompletedSources += sources; - fInfo.fPrimaryHeaderCount += primaryHeader; - fInfo.fCompletedHeaders += header; - } - } - - /** - * Updates current progress information with the provided delta. - */ - protected final void incrementRequestedFilesCount(int delta) { - synchronized (fInfo) { - fInfo.fRequestedFilesCount += delta; - } - } + protected abstract void reportFileWrittenToIndex(FileInAST file, IIndexFragmentFile ifile); private String getLocationInfo(String filename, int lineNumber) { return " at " + filename + "(" + lineNumber + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/TeamPDOMImportOperation.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/TeamPDOMImportOperation.java index 65c286d4943..cc216f892e7 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/TeamPDOMImportOperation.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/TeamPDOMImportOperation.java @@ -275,7 +275,6 @@ public class TeamPDOMImportOperation implements IWorkspaceRunnable { IResource r= fc.fFile.getResource(); if (r != null) { file.setTimestamp(r.getLocalTimeStamp()); - file.setScannerConfigurationHashcode(0); } } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/WritablePDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/WritablePDOM.java index 8de0cb7e20d..80f3ee36415 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/WritablePDOM.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/WritablePDOM.java @@ -1,14 +1,14 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2011 Wind River Systems, Inc. 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 * * Contributors: - * Markus Schorn - initial API and implementation - * Andrew Ferguson (Symbian) - * Sergey Prigogin (Google) + * Markus Schorn - initial API and implementation + * Andrew Ferguson (Symbian) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom; @@ -18,14 +18,20 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.index.IIndexFileLocation; import org.eclipse.cdt.core.index.IIndexLocationConverter; +import org.eclipse.cdt.core.parser.ISignificantMacros; +import org.eclipse.cdt.internal.core.index.FileContentKey; import org.eclipse.cdt.internal.core.index.IIndexFragment; import org.eclipse.cdt.internal.core.index.IIndexFragmentFile; -import org.eclipse.cdt.internal.core.index.IWritableIndexFragment; import org.eclipse.cdt.internal.core.index.IWritableIndex.IncludeInformation; +import org.eclipse.cdt.internal.core.index.IWritableIndexFragment; import org.eclipse.cdt.internal.core.pdom.db.BTree; import org.eclipse.cdt.internal.core.pdom.db.ChunkCache; import org.eclipse.cdt.internal.core.pdom.db.DBProperties; @@ -45,7 +51,7 @@ public class WritablePDOM extends PDOM implements IWritableIndexFragment { private ASTFilePathResolver fPathResolver; private PDOMFile fileBeingUpdated; private PDOMFile uncommittedFile; - private IIndexFileLocation uncommittedLocation; + private FileContentKey uncommittedKey; public WritablePDOM(File dbPath, IIndexLocationConverter locationConverter, Map linkageFactoryMappings) throws CoreException { @@ -62,39 +68,43 @@ public class WritablePDOM extends PDOM implements IWritableIndexFragment { } @Override - public IIndexFragmentFile addFile(int linkageID, IIndexFileLocation location) throws CoreException { - if (uncommittedLocation != null && uncommittedLocation.equals(location)) { + public IIndexFragmentFile addFile(int linkageID, IIndexFileLocation location, ISignificantMacros sigMacros) throws CoreException { + if (uncommittedKey != null && uncommittedKey.equals(new FileContentKey(linkageID, location, sigMacros))) return uncommittedFile; - } - return super.addFile(linkageID, location); + + return super.addFile(linkageID, location, sigMacros); } - public IIndexFragmentFile addUncommittedFile(int linkageID, IIndexFileLocation location) throws CoreException { - uncommittedLocation = location; - fileBeingUpdated = getFile(linkageID, uncommittedLocation); + public IIndexFragmentFile addUncommittedFile(int linkageID, IIndexFileLocation location, + ISignificantMacros significantMacros) throws CoreException { + uncommittedKey = new FileContentKey(linkageID, location, significantMacros); + fileBeingUpdated = getFile(linkageID, location, significantMacros); PDOMLinkage linkage= createLinkage(linkageID); - uncommittedFile = new PDOMFile(linkage, location, linkageID); + uncommittedFile = new PDOMFile(linkage, location, linkageID, significantMacros); return uncommittedFile; } public IIndexFragmentFile commitUncommittedFile() throws CoreException { if (uncommittedFile == null) return null; - IIndexFragmentFile file; + PDOMFile file; + BTree fileIndex = getFileIndex(); if (fileBeingUpdated == null) { // New file. - BTree fileIndex = getFileIndex(); - fileIndex.insert(uncommittedFile.getRecord()); file = uncommittedFile; } else { // Existing file. + // Remove the file from the index before replacing its contents since position of + // the file in the index is content-dependent. + fileIndex.delete(fileBeingUpdated.getRecord()); fileBeingUpdated.replaceContentsFrom(uncommittedFile); file = fileBeingUpdated; fileBeingUpdated = null; } - fEvent.fFilesWritten.add(uncommittedLocation); + fileIndex.insert(file.getRecord()); // Insert the file to the file index. + fEvent.fFilesWritten.add(uncommittedKey.getLocation()); uncommittedFile = null; - uncommittedLocation = null; + uncommittedKey = null; return file; } @@ -105,7 +115,7 @@ public class WritablePDOM extends PDOM implements IWritableIndexFragment { uncommittedFile.delete(); } finally { uncommittedFile = null; - uncommittedLocation = null; + uncommittedKey = null; fileBeingUpdated = null; } } @@ -137,9 +147,11 @@ public class WritablePDOM extends PDOM implements IWritableIndexFragment { public void clearFile(IIndexFragmentFile file, Collection contextsRemoved) throws CoreException { assert file.getIndexFragment() == this; - ((PDOMFile) file).clear(contextsRemoved); - - fEvent.fClearedFiles.add(file.getLocation()); + IIndexFileLocation location = file.getLocation(); + PDOMFile pdomFile = (PDOMFile) file; + pdomFile.clear(contextsRemoved); + + fEvent.fClearedFiles.add(location); } @Override @@ -165,9 +177,9 @@ public class WritablePDOM extends PDOM implements IWritableIndexFragment { } /** - * Use the specified location converter to update each internal representation of a file location. - * The file index is rebuilt with the new representations. Individual PDOMFile records are unmoved so - * as to maintain referential integrity with other PDOM records. + * Uses the specified location converter to update each internal representation of a file + * location. The file index is rebuilt with the new representations. Individual PDOMFile records + * are unmoved so as to maintain referential integrity with other PDOM records. * * A write-lock must be obtained before calling this method * @@ -227,16 +239,34 @@ public class WritablePDOM extends PDOM implements IWritableIndexFragment { return false; } - public PDOMFile getFileForASTPath(int linkageID, String astPath) throws CoreException { - if (fPathResolver != null && astPath != null) { - IIndexFileLocation location = fPathResolver.resolveASTPath(astPath); - if (location.equals(uncommittedLocation)) - return fileBeingUpdated != null ? fileBeingUpdated : uncommittedFile; - return getFile(linkageID, location); + public PDOMFile getFileForASTNode(int linkageID, IASTNode node) throws CoreException { + if (fPathResolver != null && node != null) { + IASTFileLocation loc= node.getFileLocation(); + if (loc != null) { + ISignificantMacros sigMacros= getSignificantMacros(node, loc); + if (sigMacros != null) { + IIndexFileLocation location = fPathResolver.resolveASTPath(loc.getFileName()); + if (uncommittedKey != null && uncommittedKey.equals(new FileContentKey(linkageID, location, sigMacros))) + return fileBeingUpdated != null ? fileBeingUpdated : uncommittedFile; + return getFile(linkageID, location, sigMacros); + } + } } return null; } + private ISignificantMacros getSignificantMacros(IASTNode node, IASTFileLocation loc) throws CoreException { + IASTPreprocessorIncludeStatement owner= loc.getContextInclusionStatement(); + if (owner != null) + return owner.getSignificantMacros(); + + IASTTranslationUnit tu = node.getTranslationUnit(); + if (tu != null) + return tu.getSignificantMacros(); + + return null; + } + @Override public boolean hasLastingDefinition(PDOMBinding binding) throws CoreException { if (fileBeingUpdated == null) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMASTAdapter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMASTAdapter.java index 5e11beb7dc2..8d630540efd 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMASTAdapter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMASTAdapter.java @@ -22,6 +22,7 @@ import org.eclipse.cdt.core.dom.ast.IASTImageLocation; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.ICompositeType; @@ -73,6 +74,10 @@ public class PDOMASTAdapter { public int getNodeOffset() { return loc.getNodeOffset(); } + + public IASTPreprocessorIncludeStatement getContextInclusionStatement() { + return loc.getContextInclusionStatement(); + } }; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMFile.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMFile.java index f8368489476..e05129ab740 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMFile.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMFile.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2010 QNX Software Systems and others. + * Copyright (c) 2005, 2011 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 @@ -37,12 +37,14 @@ import org.eclipse.cdt.core.index.IIndexInclude; import org.eclipse.cdt.core.index.IIndexLocationConverter; import org.eclipse.cdt.core.index.IIndexMacro; import org.eclipse.cdt.core.index.IIndexName; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.internal.core.index.IIndexFragment; import org.eclipse.cdt.internal.core.index.IIndexFragmentFile; import org.eclipse.cdt.internal.core.index.IIndexFragmentName; import org.eclipse.cdt.internal.core.index.IWritableIndex.IncludeInformation; import org.eclipse.cdt.internal.core.index.IWritableIndexFragment; import org.eclipse.cdt.internal.core.index.IndexFileLocation; +import org.eclipse.cdt.internal.core.parser.scanner.SignificantMacros; import org.eclipse.cdt.internal.core.pdom.PDOM; import org.eclipse.cdt.internal.core.pdom.YieldableIndexLock; import org.eclipse.cdt.internal.core.pdom.db.BTree; @@ -56,28 +58,31 @@ import org.eclipse.core.runtime.Status; /** * Represents a file containing names. - * + * * @author Doug Schaefer */ public class PDOMFile implements IIndexFragmentFile { private final PDOMLinkage fLinkage; private final long record; - private IIndexFileLocation location; // No need to make volatile, all fields of IIndexFileLocation are final. + private IIndexFileLocation location; // No need to make volatile, all fields of IndexFileLocation are final. + private ISignificantMacros sigMacros; // No need to make volatile, all fields of FileContentsKey are either final or volatile. private static final int FIRST_NAME = 0; - private static final int FIRST_INCLUDE = 4; - private static final int FIRST_INCLUDED_BY = 8; - private static final int FIRST_MACRO = 12; - private static final int LOCATION_REPRESENTATION = 16; - private static final int LINKAGE_ID= 20; - private static final int TIME_STAMP = 24; - private static final int CONTENT_HASH= 32; - private static final int SCANNER_CONFIG_HASH= 40; - private static final int ENCODING_HASH= 44; - private static final int LAST_USING_DIRECTIVE= 48; - private static final int FIRST_MACRO_REFERENCE= 52; + private static final int FIRST_INCLUDE = FIRST_NAME + Database.PTR_SIZE; + private static final int FIRST_INCLUDED_BY = FIRST_INCLUDE + Database.PTR_SIZE; + private static final int FIRST_MACRO = FIRST_INCLUDED_BY + Database.PTR_SIZE; + private static final int LOCATION_REPRESENTATION = FIRST_MACRO + Database.PTR_SIZE; + private static final int LINKAGE_ID= LOCATION_REPRESENTATION + Database.PTR_SIZE; // size 3 + private static final int FLAGS= LINKAGE_ID + 3; // size 1 + private static final int TIME_STAMP = FLAGS + 1; // long + private static final int CONTENT_HASH= TIME_STAMP + 8; // long + private static final int ENCODING_HASH= CONTENT_HASH + 8; + private static final int LAST_USING_DIRECTIVE= ENCODING_HASH + 4; + private static final int FIRST_MACRO_REFERENCE= LAST_USING_DIRECTIVE + Database.PTR_SIZE; + private static final int SIGNIFICANT_MACROS= FIRST_MACRO_REFERENCE + Database.PTR_SIZE; + private static final int RECORD_SIZE= SIGNIFICANT_MACROS + Database.PTR_SIZE; // 8*PTR_SIZE + 3+1+8+8+4 = 56 - private static final int RECORD_SIZE= 56; + private static final int FLAG_PRAGMA_ONCE_SEMANTICS = 0x01; public static class Comparator implements IBTreeComparator { private Database db; @@ -91,10 +96,26 @@ public class PDOMFile implements IIndexFragmentFile { IString name2 = db.getString(db.getRecPtr(record2 + LOCATION_REPRESENTATION)); int cmp= name1.compare(name2, true); if (cmp == 0) { - cmp= db.getInt(record1 + LINKAGE_ID) - db.getInt(record2 + LINKAGE_ID); + cmp= db.get3ByteUnsignedInt(record1 + LINKAGE_ID) - db.get3ByteUnsignedInt(record2 + LINKAGE_ID); + if (cmp == 0) { + IString sm1= getString(record1 + SIGNIFICANT_MACROS); + IString sm2= getString(record2 + SIGNIFICANT_MACROS); + if (sm1 == null) { + cmp= sm2 == null ? 0 : -1; + } else if (sm2 == null) { + cmp= 1; + } else { + cmp= sm1.compare(sm2, true); + } + } } return cmp; } + + private IString getString(long offset) throws CoreException { + long rec = db.getRecPtr(offset); + return rec != 0 ? db.getString(rec) : null; + } } public PDOMFile(PDOMLinkage linkage, long record) { @@ -102,7 +123,7 @@ public class PDOMFile implements IIndexFragmentFile { this.record = record; } - public PDOMFile(PDOMLinkage linkage, IIndexFileLocation location, int linkageID) throws CoreException { + public PDOMFile(PDOMLinkage linkage, IIndexFileLocation location, int linkageID, ISignificantMacros macros) throws CoreException { fLinkage = linkage; this.location= location; Database db = fLinkage.getDB(); @@ -112,7 +133,8 @@ public class PDOMFile implements IIndexFragmentFile { throw new CoreException(CCorePlugin.createStatus(Messages.getString("PDOMFile.toInternalProblem") + location.getURI())); //$NON-NLS-1$ IString locationDBString = db.newString(locationString); db.putRecPtr(record + LOCATION_REPRESENTATION, locationDBString.getRecord()); - db.putInt(record + LINKAGE_ID, linkageID); + db.put3ByteUnsignedInt(record + LINKAGE_ID, linkageID); + db.putRecPtr(record + SIGNIFICANT_MACROS, db.newString(macros.encode()).getRecord()); setTimestamp(-1); } @@ -123,7 +145,7 @@ public class PDOMFile implements IIndexFragmentFile { public PDOM getPDOM() { return fLinkage.getPDOM(); } - + @Override public boolean equals(Object obj) { if (obj == this) @@ -139,7 +161,7 @@ public class PDOMFile implements IIndexFragmentFile { public final int hashCode() { return System.identityHashCode(fLinkage.getPDOM()) + (int) (41 * record); } - + /** * Transfers names, macros and includes from another file to this one and deletes the other file. * @param sourceFile the file to transfer the local bindings from. @@ -227,7 +249,10 @@ public class PDOMFile implements IIndexFragmentFile { setTimestamp(sourceFile.getTimestamp()); setEncodingHashcode(sourceFile.getEncodingHashcode()); setContentsHash(sourceFile.getContentsHash()); - setScannerConfigurationHashcode(sourceFile.getScannerConfigurationHashcode()); + + Database db= fLinkage.getDB(); + // Transfer the flags. + db.putByte(record + FLAGS, db.getByte(sourceFile.record + FLAGS)); sourceFile.delete(); } @@ -239,9 +264,10 @@ public class PDOMFile implements IIndexFragmentFile { */ public void setLocation(IIndexFileLocation location) throws CoreException { String locationString = fLinkage.getPDOM().getLocationConverter().toInternalFormat(location); - if (locationString == null) + if (locationString == null) { throw new CoreException(CCorePlugin.createStatus(Messages.getString("PDOMFile.toInternalProblem") + //$NON-NLS-1$ location.getURI())); + } setInternalLocation(locationString); } @@ -260,10 +286,10 @@ public class PDOMFile implements IIndexFragmentFile { db.putRecPtr(record + LOCATION_REPRESENTATION, db.newString(internalLocation).getRecord()); location= null; } - + public int getLinkageID() throws CoreException { Database db = fLinkage.getDB(); - return db.getInt(record + LINKAGE_ID); + return db.get3ByteUnsignedInt(record + LINKAGE_ID); } public long getTimestamp() throws CoreException { @@ -287,13 +313,7 @@ public class PDOMFile implements IIndexFragmentFile { } public int getScannerConfigurationHashcode() throws CoreException { - Database db = fLinkage.getDB(); - return db.getInt(record + SCANNER_CONFIG_HASH); - } - - public void setScannerConfigurationHashcode(int hashcode) throws CoreException { - Database db= fLinkage.getDB(); - db.putInt(record + SCANNER_CONFIG_HASH, hashcode); + return 0; } public int getEncodingHashcode() throws CoreException { @@ -306,6 +326,21 @@ public class PDOMFile implements IIndexFragmentFile { db.putInt(record + ENCODING_HASH, hashcode); } + public boolean hasPragmaOnceSemantics() throws CoreException { + return (fLinkage.getDB().getByte(record + FLAGS) & FLAG_PRAGMA_ONCE_SEMANTICS) != 0; + } + + public void setPragmaOnceSemantics(boolean value) throws CoreException { + Database db = fLinkage.getDB(); + byte flags = db.getByte(record + FLAGS); + if (value) { + flags |= FLAG_PRAGMA_ONCE_SEMANTICS; + } else { + flags &= ~FLAG_PRAGMA_ONCE_SEMANTICS; + } + db.putByte(record + FLAGS, flags); + } + private PDOMName getFirstName() throws CoreException { long namerec = fLinkage.getDB().getRecPtr(record + FIRST_NAME); return namerec != 0 ? new PDOMName(fLinkage, namerec) : null; @@ -340,7 +375,7 @@ public class PDOMFile implements IIndexFragmentFile { long rec = fLinkage.getDB().getRecPtr(record + FIRST_INCLUDED_BY); return rec != 0 ? new PDOMInclude(fLinkage, rec) : null; } - + public IIndexInclude getParsedInContext() throws CoreException { return getFirstIncludedBy(); } @@ -515,7 +550,7 @@ public class PDOMFile implements IIndexFragmentFile { m.delete(); } setFirstMacroReference(null); - + setPragmaOnceSemantics(false); setTimestamp(-1); } @@ -527,6 +562,9 @@ public class PDOMFile implements IIndexFragmentFile { public void delete() throws CoreException { Database db = fLinkage.getDB(); long locRecord = db.getRecPtr(record + LOCATION_REPRESENTATION); + if (locRecord != 0) + db.getString(locRecord).delete(); + locRecord = db.getRecPtr(record + SIGNIFICANT_MACROS); if (locRecord != 0) db.getString(locRecord).delete(); @@ -539,7 +577,7 @@ public class PDOMFile implements IIndexFragmentFile { PDOMInclude lastInclude= null; for (final IncludeInformation info : includeInfos) { final PDOMFile targetFile= (PDOMFile) info.fTargetFile; - + PDOMInclude pdomInclude = new PDOMInclude(fLinkage, info.fStatement, this, targetFile); assert targetFile == null || targetFile.getIndexFragment() instanceof IWritableIndexFragment; if (targetFile != null) { @@ -560,7 +598,7 @@ public class PDOMFile implements IIndexFragmentFile { if (isContext) { setFirstIncludedBy(include); include.setNextInIncludedBy(firstIncludedBy); - firstIncludedBy.setPrevInIncludedBy(include); + firstIncludedBy.setPrevInIncludedBy(include); } else { PDOMInclude secondIncludedBy= firstIncludedBy.getNextInIncludedBy(); if (secondIncludedBy != null) { @@ -606,13 +644,12 @@ public class PDOMFile implements IIndexFragmentFile { if (nameOffset >= offset) { if (nameOffset + name.getNodeLength() <= offset + length) { result.add(name); - } else if (name.isReference()) { + } else if (name.isReference()) { // Names are ordered, but callers are inserted before // their references. break; } } - } for (PDOMMacro macro= getFirstMacro(); macro != null; macro= macro.getNextMacro()) { int nameOffset= macro.getNodeOffset(); @@ -622,7 +659,7 @@ public class PDOMFile implements IIndexFragmentFile { if (name != null) { result.add(name); } - } else { + } else { break; } } @@ -632,7 +669,7 @@ public class PDOMFile implements IIndexFragmentFile { if (nameOffset >= offset) { if (nameOffset + name.getNodeLength() <= offset + length) { result.add(name); - } else { + } else { break; } } @@ -640,11 +677,53 @@ public class PDOMFile implements IIndexFragmentFile { return result.toArray(new IIndexName[result.size()]); } - public static PDOMFile findFile(PDOMLinkage linkage, BTree btree, IIndexFileLocation location, + public static PDOMFile[] findFiles(PDOMLinkage linkage, BTree btree, IIndexFileLocation location, IIndexLocationConverter strategy) throws CoreException { String internalRepresentation= strategy.toInternalFormat(location); if (internalRepresentation != null) { - Finder finder = new Finder(linkage.getDB(), internalRepresentation, linkage.getLinkageID()); + Finder finder = new Finder(linkage.getDB(), internalRepresentation, linkage.getLinkageID(), null); + btree.accept(finder); + long[] records= finder.getRecords(); + PDOMFile[] result= new PDOMFile[records.length]; + for (int i = 0; i < result.length; i++) { + result[i]= new PDOMFile(linkage, records[i]); + } + return result; + } + return null; + } + + /** + * When a header file is stored in the index in multiple variants for different sets of macro + * definitions this method will return an arbitrary one of these variants. + * + * @deprecated Use + * {@link #findFile(PDOMLinkage, BTree, IIndexFileLocation, IIndexLocationConverter, ISignificantMacros)} + * or {@link #findFiles(PDOMLinkage, BTree, IIndexFileLocation, IIndexLocationConverter)} + */ + @Deprecated + public static PDOMFile findFile(PDOMLinkage linkage, BTree btree, IIndexFileLocation location, + IIndexLocationConverter strategy) throws CoreException { + return findFile(linkage, btree, location, strategy, null); + } + + /** + * Finds the file in index. + * + * @param linkage The linkage of the file. + * @param btree The file index. + * @param location The location of the file. + * @param strategy The index location converter. + * @param macroDictionary The names and definitions of the macros used to disambiguate between + * variants of the file contents corresponding to different inclusion points. + * @return The found file, or null if the matching file was not found. + */ + public static PDOMFile findFile(PDOMLinkage linkage, BTree btree, IIndexFileLocation location, + IIndexLocationConverter strategy, ISignificantMacros macroDictionary) throws CoreException { + String internalRepresentation= strategy.toInternalFormat(location); + if (internalRepresentation != null) { + Finder finder = new Finder(linkage.getDB(), internalRepresentation, linkage.getLinkageID(), + macroDictionary); btree.accept(finder); long record= finder.getRecord(); if (record != 0) { @@ -658,7 +737,7 @@ public class PDOMFile implements IIndexFragmentFile { IIndexLocationConverter strategy) throws CoreException { String internalRepresentation= strategy.toInternalFormat(location); if (internalRepresentation != null) { - Finder finder = new Finder(pdom.getDB(), internalRepresentation, -1); + Finder finder = new Finder(pdom.getDB(), internalRepresentation, -1, null); btree.accept(finder); long[] records= finder.getRecords(); PDOMFile[] result= new PDOMFile[records.length]; @@ -672,12 +751,11 @@ public class PDOMFile implements IIndexFragmentFile { public static PDOMFile recreateFile(PDOM pdom, final long record) throws CoreException { final Database db= pdom.getDB(); - final int linkageID= db.getInt(record + PDOMFile.LINKAGE_ID); + final int linkageID= db.get3ByteUnsignedInt(record + LINKAGE_ID); PDOMLinkage linkage= pdom.getLinkage(linkageID); if (linkage == null) throw new CoreException(createStatus("Invalid linkage ID in database")); //$NON-NLS-1$ - PDOMFile file= new PDOMFile(linkage, record); - return file; + return new PDOMFile(linkage, record); } private static class Finder implements IBTreeVisitor { @@ -687,14 +765,17 @@ public class PDOMFile implements IIndexFragmentFile { private long record; private long[] records; private final int linkageID; + private char[] rawSignificantMacros; /** * Searches for a file with the given linkage id. */ - public Finder(Database db, String internalRepresentation, int linkageID) { + public Finder(Database db, String internalRepresentation, int linkageID, ISignificantMacros sigMacros) { this.db = db; this.rawKey = internalRepresentation; this.linkageID= linkageID; + this.rawSignificantMacros = sigMacros == null ? null : sigMacros.encode(); + assert linkageID >= 0 || rawSignificantMacros == null; } public long[] getRecords() { @@ -706,32 +787,48 @@ public class PDOMFile implements IIndexFragmentFile { } return records; } - + public int compare(long record) throws CoreException { IString name = db.getString(db.getRecPtr(record + PDOMFile.LOCATION_REPRESENTATION)); int cmp= name.compare(rawKey, true); if (cmp == 0 && linkageID >= 0) { - cmp= db.getInt(record + PDOMFile.LINKAGE_ID) - linkageID; + cmp= db.get3ByteUnsignedInt(record + PDOMFile.LINKAGE_ID) - linkageID; + if (cmp == 0 && rawSignificantMacros != null) { + IString significantMacrosStr = getString(record + SIGNIFICANT_MACROS); + if (significantMacrosStr != null) { + cmp = significantMacrosStr.compare(rawSignificantMacros, true); + } else { + cmp = rawSignificantMacros.length > 0 ? -1 : 0; + } + } } return cmp; } - + + private IString getString(long offset) throws CoreException { + long rec = db.getRecPtr(offset); + return rec != 0 ? db.getString(rec) : null; + } + public boolean visit(long record) throws CoreException { - if (linkageID >= 0) { + if (rawSignificantMacros != null) { this.record = record; - return false; + return false; + // Stop searching. } + if (this.record == 0) { this.record= record; } else if (this.records == null) { - this.records= new long[] {this.record, record}; + this.records= new long[] { this.record, record }; } else { long[] cpy= new long[this.records.length + 1]; System.arraycopy(this.records, 0, cpy, 0, this.records.length); cpy[cpy.length - 1]= record; this.records= cpy; } - return linkageID < 0; + // Continue search. + return true; } public long getRecord() { @@ -757,7 +854,22 @@ public class PDOMFile implements IIndexFragmentFile { } return location; } + + public ISignificantMacros getSignificantMacros() throws CoreException { + if (sigMacros == null) { + Database db= fLinkage.getDB(); + final IString encoded = db.getString(db.getRecPtr(record + SIGNIFICANT_MACROS)); + sigMacros= encoded == null ? ISignificantMacros.NONE : new SignificantMacros(encoded.getChars()); + } + return sigMacros; + } + + + public boolean isComplete() { + return true; + } + public boolean hasContent() throws CoreException { return getTimestamp() != -1; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMLinkage.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMLinkage.java index 35cc42ef67b..78d13b8b15b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMLinkage.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMLinkage.java @@ -256,9 +256,9 @@ public abstract class PDOMLinkage extends PDOMNamedNode implements IIndexLinkage } if (checkIfInSourceOnly) { - String path= ASTInternal.getDeclaredInSourceFileOnly(binding, requireDefinition, glob); - if (path != null) { - return wpdom.getFileForASTPath(getLinkageID(), path); + IASTNode node= ASTInternal.getDeclaredInSourceFileOnly(binding, requireDefinition, glob); + if (node != null) { + return wpdom.getFileForASTNode(getLinkageID(), node); } } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacro.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacro.java index 7ea5c88564d..8f8b0a6f10d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacro.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacro.java @@ -20,6 +20,7 @@ import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IPDOMVisitor; import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorUndefStatement; import org.eclipse.cdt.core.dom.ast.IMacroBinding; @@ -278,10 +279,6 @@ public class PDOMMacro implements IIndexMacro, IPDOMBinding, IASTFileLocation { fLinkage.getDB().putRecPtr(fRecord + FILE, file != null ? file.getRecord() : 0); } - public int getEndingLineNumber() { - return 0; - } - public String getFileName() { try { IIndexFile file = getFile(); @@ -303,6 +300,14 @@ public class PDOMMacro implements IIndexMacro, IPDOMBinding, IASTFileLocation { return 0; } + public int getEndingLineNumber() { + return 0; + } + + public IASTPreprocessorIncludeStatement getContextInclusionStatement() { + return null; + } + public IASTFileLocation asFileLocation() { return this; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacroReferenceName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacroReferenceName.java index dc2807e21d4..ff242e63d2e 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacroReferenceName.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacroReferenceName.java @@ -15,6 +15,7 @@ package org.eclipse.cdt.internal.core.pdom.dom; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; import org.eclipse.cdt.core.index.IIndexFile; import org.eclipse.cdt.core.index.IIndexName; import org.eclipse.cdt.core.index.IndexLocationFactory; @@ -216,6 +217,10 @@ public final class PDOMMacroReferenceName implements IIndexFragmentName, IASTFil return 0; } + public IASTPreprocessorIncludeStatement getContextInclusionStatement() { + return null; + } + public IASTFileLocation asFileLocation() { return this; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMName.java index f8a5bb59273..cad23af7f64 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMName.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMName.java @@ -6,9 +6,9 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Doug Schaefer (QNX) - Initial API and implementation - * Markus Schorn (Wind River Systems) - * Sergey Prigogin (Google) + * Doug Schaefer (QNX) - Initial API and implementation + * Markus Schorn (Wind River Systems) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom.dom; @@ -17,6 +17,7 @@ import java.util.ArrayList; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; import org.eclipse.cdt.core.index.IIndexFile; import org.eclipse.cdt.core.index.IIndexName; import org.eclipse.cdt.core.index.IndexLocationFactory; @@ -323,6 +324,10 @@ public final class PDOMName implements IIndexFragmentName, IASTFileLocation { return 0; } + public IASTPreprocessorIncludeStatement getContextInclusionStatement() { + return null; + } + public IASTFileLocation asFileLocation() { return this; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java index 8b7dab40caf..b2c6acfcc90 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java @@ -969,23 +969,23 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants { final WritablePDOM wpdom= (WritablePDOM) pdom; PDOMFile file= null; if (binding instanceof ICPPUsingDeclaration) { - String path= ASTInternal.getDeclaredInOneFileOnly(binding); - if (path != null) { - file= wpdom.getFileForASTPath(getLinkageID(), path); + IASTNode node= ASTInternal.getDeclaredInOneFileOnly(binding); + if (node != null) { + file= wpdom.getFileForASTNode(getLinkageID(), node); } } else if (binding instanceof ICPPNamespaceAlias) { - String path= ASTInternal.getDeclaredInSourceFileOnly(binding, false, glob); - if (path != null) { - file= wpdom.getFileForASTPath(getLinkageID(), path); + IASTNode node= ASTInternal.getDeclaredInSourceFileOnly(binding, false, glob); + if (node != null) { + file= wpdom.getFileForASTNode(getLinkageID(), node); } } if (file == null && !(binding instanceof IIndexBinding)) { IBinding owner= binding.getOwner(); if (owner instanceof ICPPNamespace) { if (owner.getNameCharArray().length == 0) { - String path= ASTInternal.getDeclaredInSourceFileOnly(owner, false, glob); - if (path != null) { - file= wpdom.getFileForASTPath(getLinkageID(), path); + IASTNode node= ASTInternal.getDeclaredInSourceFileOnly(owner, false, glob); + if (node != null) { + file= wpdom.getFileForASTNode(getLinkageID(), node); } } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/AbstractPDOMIndexer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/AbstractPDOMIndexer.java index b17b9f9f522..34140806933 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/AbstractPDOMIndexer.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/AbstractPDOMIndexer.java @@ -21,6 +21,9 @@ import org.eclipse.cdt.core.model.ICProject; * Abstract base class for all indexers. */ public abstract class AbstractPDOMIndexer implements IPDOMIndexer { + // For testing purposes + public static boolean noFilesUpFront= false; + protected ICProject project; protected Properties fProperties= new Properties(); @@ -82,11 +85,13 @@ public abstract class AbstractPDOMIndexer implements IPDOMIndexer { } public String[] getFilesToParseUpFront() { - String prefSetting= getProperty(IndexerPreferences.KEY_FILES_TO_PARSE_UP_FRONT); - if (prefSetting != null) { - prefSetting= prefSetting.trim(); - if (prefSetting.length() > 0) { - return prefSetting.split(","); //$NON-NLS-1$ + if (!noFilesUpFront) { + String prefSetting= getProperty(IndexerPreferences.KEY_FILES_TO_PARSE_UP_FRONT); + if (prefSetting != null) { + prefSetting= prefSetting.trim(); + if (prefSetting.length() > 0) { + return prefSetting.split(","); //$NON-NLS-1$ + } } } return new String[0]; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/PDOMIndexerTask.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/PDOMIndexerTask.java index 9fba3a7cd2c..2b1f12d0771 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/PDOMIndexerTask.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/PDOMIndexerTask.java @@ -40,7 +40,6 @@ import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; @@ -177,16 +176,6 @@ public abstract class PDOMIndexerTask extends AbstractIndexerTask implements IPD return defaultValue; } - @Override - protected String getASTPathForParsingUpFront() { - final IProject project = getProject().getProject(); - final IPath prjLocation= project.getLocation(); - if (prjLocation == null) { - return null; - } - return prjLocation.append(super.getASTPathForParsingUpFront()).toString(); - } - @Override protected AbstractLanguage[] getLanguages(String filename) { IProject project = getProject().getProject(); @@ -406,4 +395,4 @@ public abstract class PDOMIndexerTask extends AbstractIndexerTask implements IPD } return super.acceptUrgentTask(urgentTask); } -} \ No newline at end of file +} diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/parser/ParserLogService.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/parser/ParserLogService.java index 5f6eb04e6b0..c08ca43d547 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/parser/ParserLogService.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/parser/ParserLogService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2002, 2008 IBM Corporation and others. + * Copyright (c) 2002, 2011 IBM Corporation 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 @@ -19,6 +19,7 @@ import org.eclipse.cdt.internal.core.model.DebugLogConstants; import org.eclipse.cdt.internal.core.model.Util; import org.eclipse.cdt.internal.core.util.ICancelable; import org.eclipse.cdt.internal.core.util.ICanceler; +import org.eclipse.core.runtime.Platform; /** * @author jcamelon @@ -53,6 +54,16 @@ public class ParserLogService extends AbstractParserLogService implements ICance Util.debugLog( message, topic ); } + @Override + public boolean isTracing(String option) { + return "true".equals(Platform.getDebugOption(option)); //$NON-NLS-1$ + } + + @Override + public void traceLog(String option, String message) { + if (isTracing(option)) + System.out.println(message); + } @Override public void errorLog(String message) {