diff options
author | Sergey Prigogin | 2011-10-17 22:19:11 +0000 |
---|---|---|
committer | Sergey Prigogin | 2011-10-17 22:19:11 +0000 |
commit | c2cec226b35aeae02216daa1153727b95419e215 (patch) | |
tree | 9b02feba27764869398494123732c0abcc5b2fc9 | |
parent | ba9b696a073f9f45244fe830ddf9e3c0cca31ae0 (diff) | |
parent | 4e65505eba8f70fd8f114fbda81a1cae41223c53 (diff) | |
download | org.eclipse.cdt-c2cec226b35aeae02216daa1153727b95419e215.tar.gz org.eclipse.cdt-c2cec226b35aeae02216daa1153727b95419e215.tar.xz org.eclipse.cdt-c2cec226b35aeae02216daa1153727b95419e215.zip |
Merge branch 'bug_197989_B'
91 files changed, 4346 insertions, 1770 deletions
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 <string> + // + // 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..ed65bacc85c 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); 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/IndexBindingResolutionTestBase.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBindingResolutionTestBase.java index 54bf1201d2f..ffe5e705c22 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBindingResolutionTestBase.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBindingResolutionTestBase.java @@ -6,13 +6,16 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Andrew Ferguson (Symbian) - Initial implementation - * IBM Corporation - * Markus Schorn (Wind River Systems) + * Andrew Ferguson (Symbian) - Initial implementation + * IBM Corporation + * Markus Schorn (Wind River Systems) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.index.tests; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IPDOMManager; @@ -81,14 +84,19 @@ public abstract class IndexBindingResolutionTestBase extends BaseTestCase { } protected IASTName findName(String section, int len) { - IASTTranslationUnit ast = strategy.getAst(); - final IASTNodeSelector nodeSelector = ast.getNodeSelector(null); - final int offset = strategy.getTestData()[1].indexOf(section); - IASTName name= nodeSelector.findName(offset, len); - if (name == null) - name= nodeSelector.findImplicitName(offset, len); + for (int i = 0; i < strategy.getAstCount(); i++) { + IASTTranslationUnit ast = strategy.getAst(i); + final IASTNodeSelector nodeSelector = ast.getNodeSelector(null); + final int offset = strategy.getAstSource(i).indexOf(section); + if (offset >= 0) { + IASTName name= nodeSelector.findName(offset, len); + if (name == null) + name= nodeSelector.findImplicitName(offset, len); + return name; + } + } - return name; + return null; } /** @@ -210,7 +218,9 @@ public abstract class IndexBindingResolutionTestBase extends BaseTestCase { IIndex getIndex(); void setUp() throws Exception; void tearDown() throws Exception; - public IASTTranslationUnit getAst(); + public int getAstCount(); + public IASTTranslationUnit getAst(int index); + public StringBuilder getAstSource(int index); public StringBuilder[] getTestData(); public ICProject getCProject(); public boolean isCompositeIndex(); @@ -258,13 +268,25 @@ public abstract class IndexBindingResolutionTestBase extends BaseTestCase { return testData; } - public IASTTranslationUnit getAst() { + public int getAstCount() { + return 1; + } + + public IASTTranslationUnit getAst(int index) { + if (index != 0) + throw new IllegalArgumentException(); return ast; } + public StringBuilder getAstSource(int index) { + if (index != 0) + throw new IllegalArgumentException(); + return testData[1]; + } + public void setUp() throws Exception { - cproject = cpp ? CProjectHelper.createCCProject(getName()+System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER) - : CProjectHelper.createCProject(getName()+System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER); + cproject = cpp ? CProjectHelper.createCCProject(getName() + System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER) + : CProjectHelper.createCProject(getName() + System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER); Bundle b = CTestPlugin.getDefault().getBundle(); testData = TestSourceReader.getContentsForTest(b, "parser", IndexBindingResolutionTestBase.this.getClass(), getName(), 2); @@ -275,7 +297,7 @@ public abstract class IndexBindingResolutionTestBase extends BaseTestCase { assertTrue(CCorePlugin.getIndexManager().joinIndexer(360000, new NullProgressMonitor())); if (DEBUG) { - System.out.println("Project PDOM: "+getName()); + System.out.println("Project PDOM: " + getName()); ((PDOM)CCoreInternals.getPDOMManager().getPDOM(cproject)).accept(new PDOMPrettyPrinter()); } @@ -304,7 +326,6 @@ public abstract class IndexBindingResolutionTestBase extends BaseTestCase { } } - class SinglePDOMTestStrategy implements ITestStrategy { private IIndex index; private ICProject cproject; @@ -324,10 +345,22 @@ public abstract class IndexBindingResolutionTestBase extends BaseTestCase { return testData; } - public IASTTranslationUnit getAst() { + public int getAstCount() { + return 1; + } + + public IASTTranslationUnit getAst(int index) { + if (index != 0) + throw new IllegalArgumentException(); return ast; } + public StringBuilder getAstSource(int index) { + if (index != 0) + throw new IllegalArgumentException(); + return testData[1]; + } + public void setUp() throws Exception { cproject = cpp ? CProjectHelper.createCCProject(getName()+System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER) : CProjectHelper.createCProject(getName()+System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER); @@ -370,6 +403,108 @@ public abstract class IndexBindingResolutionTestBase extends BaseTestCase { } } + /** + * This strategy allows tests to create an arbitrary number of header and source files + * and to obtain ASTs of any subset of the created files. + * + * The first line of each comment section preceding the test contains the name of the file + * to put the contents of the section to. To request the AST of a file, put an asterisk after + * the file name. + */ + class SinglePDOMTestNamedFilesStrategy implements ITestStrategy { + private IIndex index; + private ICProject cproject; + private StringBuilder[] testData; + private final List<StringBuilder> astSources; + private final List<IASTTranslationUnit> asts; + private final boolean cpp; + + public SinglePDOMTestNamedFilesStrategy(boolean cpp) { + this.cpp = cpp; + astSources = new ArrayList<StringBuilder>(); + asts = new ArrayList<IASTTranslationUnit>(); + } + + public ICProject getCProject() { + return cproject; + } + + public StringBuilder[] getTestData() { + return testData; + } + + public int getAstCount() { + return asts.size(); + } + + public IASTTranslationUnit getAst(int index) { + return asts.get(index); + } + + public StringBuilder getAstSource(int index) { + return astSources.get(index); + } + + public void setUp() throws Exception { + cproject = cpp ? CProjectHelper.createCCProject(getName() + System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER) + : CProjectHelper.createCProject(getName() + System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER); + Bundle b = CTestPlugin.getDefault().getBundle(); + testData = TestSourceReader.getContentsForTest(b, "parser", IndexBindingResolutionTestBase.this.getClass(), getName(), 0); + + List<IFile> astFiles = new ArrayList<IFile>(); + for (int i = 0; i < testData.length; i++) { + StringBuilder contents = testData[i]; + int endOfLine = contents.indexOf("\n"); + if (endOfLine >= 0) + endOfLine++; + else + endOfLine = contents.length(); + String filename = contents.substring(0, endOfLine).trim(); + contents.delete(0, endOfLine); // Remove first line from the file contents + boolean astRequested = filename.endsWith("*"); + if (astRequested) { + filename = filename.substring(0, filename.length() - 1).trim(); + } + IFile file = TestSourceReader.createFile(cproject.getProject(), new Path(filename), contents.toString()); + if (astRequested || (i == testData.length - 1 && astFiles.isEmpty())) { + astSources.add(contents); + astFiles.add(file); + } + } + CCorePlugin.getIndexManager().setIndexerId(cproject, IPDOMManager.ID_FAST_INDEXER); + assertTrue(CCorePlugin.getIndexManager().joinIndexer(360000, new NullProgressMonitor())); + + if (DEBUG) { + System.out.println("Project PDOM: "+getName()); + ((PDOM) CCoreInternals.getPDOMManager().getPDOM(cproject)).accept(new PDOMPrettyPrinter()); + } + + index= CCorePlugin.getIndexManager().getIndex(cproject); + + index.acquireReadLock(); + for (IFile file : astFiles) { + asts.add(TestSourceReader.createIndexBasedAST(index, cproject, file)); + } + } + + public void tearDown() throws Exception { + if (index != null) { + index.releaseReadLock(); + } + if (cproject != null) { + cproject.getProject().delete(IResource.FORCE | IResource.ALWAYS_DELETE_PROJECT_CONTENT, new NullProgressMonitor()); + } + } + + public IIndex getIndex() { + return index; + } + + public boolean isCompositeIndex() { + return false; + } + } + class ReferencedProject implements ITestStrategy { private IIndex index; private ICProject cproject, referenced; @@ -445,10 +580,22 @@ public abstract class IndexBindingResolutionTestBase extends BaseTestCase { return referenced; } - public IASTTranslationUnit getAst() { + public int getAstCount() { + return 1; + } + + public IASTTranslationUnit getAst(int index) { + if (index != 0) + throw new IllegalArgumentException(); return ast; } + public StringBuilder getAstSource(int index) { + if (index != 0) + throw new IllegalArgumentException(); + return testData[1]; + } + public IIndex getIndex() { return index; } 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..293cbc8ae73 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 @@ -289,6 +289,17 @@ public class IndexBugsTests extends BaseTestCase { return TestSourceReader.createFile(container, new Path(fileName), contents); } + private IIndexFile getIndexFile(IFile file) throws CoreException { + return getIndexFile(fIndex, file); + } + + private IIndexFile getIndexFile(IIndex index, IFile file) throws CoreException { + IIndexFile[] files = index.getFiles(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(file)); + assertTrue("Can't find " + file.getLocation(), files.length > 0); + assertEquals("Found " + files.length + " files for " + file.getLocation() + " instead of one", 1, files.length); + return files[0]; + } + private void waitForIndexer() throws InterruptedException { final IIndexManager indexManager = CCorePlugin.getIndexManager(); assertTrue(indexManager.joinIndexer(INDEX_WAIT_TIME, npm())); @@ -459,8 +470,7 @@ public class IndexBugsTests extends BaseTestCase { fIndex.acquireReadLock(); try { - IIndexFile ifile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(file)); - assertNotNull(ifile); + IIndexFile ifile= getIndexFile(file); IIndexInclude[] includes= ifile.getIncludes(); assertEquals(1, includes.length); IIndexInclude i= includes[0]; @@ -484,8 +494,7 @@ public class IndexBugsTests extends BaseTestCase { fIndex.acquireReadLock(); try { - IIndexFile ifile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(file)); - assertNotNull(ifile); + IIndexFile ifile= getIndexFile(file); IIndexInclude[] includes= ifile.getIncludes(); assertEquals(1, includes.length); IIndexInclude i= includes[0]; @@ -561,8 +570,7 @@ public class IndexBugsTests extends BaseTestCase { fIndex.acquireReadLock(); try { - IIndexFile ifile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(file)); - assertNotNull(ifile); + IIndexFile ifile= getIndexFile(file); IIndexInclude[] includes= ifile.getIncludes(); assertEquals(1, includes.length); IIndexInclude i= includes[0]; @@ -585,8 +593,7 @@ public class IndexBugsTests extends BaseTestCase { fIndex.acquireReadLock(); try { - IIndexFile ifile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(file)); - assertNotNull(ifile); + IIndexFile ifile= getIndexFile(file); IIndexInclude[] includes= ifile.getIncludes(); assertEquals(1, includes.length); IIndexInclude i= includes[0]; @@ -612,8 +619,7 @@ public class IndexBugsTests extends BaseTestCase { fIndex.acquireReadLock(); try { - IIndexFile ifile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(file)); - assertNotNull(ifile); + IIndexFile ifile= getIndexFile(file); IIndexMacro[] macros= ifile.getMacros(); assertEquals(3, macros.length); IIndexMacro m= macros[0]; @@ -1116,7 +1122,7 @@ public class IndexBugsTests extends BaseTestCase { // #endif // #ifndef _h1 - // #include "header1.h" + // #include "header1.h" // is inactive, but must be resolved // #endif // #include "header1.h" @@ -1127,7 +1133,7 @@ public class IndexBugsTests extends BaseTestCase { // #include "header2.h" // #ifndef _h1 - // #include "header1.h" + // #include "header1.h" // inactive but resolved. // #endif public void testIncludeGuardsOutsideOfHeader_Bug167100() throws Exception { final IIndexManager indexManager = CCorePlugin.getIndexManager(); @@ -1152,13 +1158,15 @@ 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(f5)); + assertEquals(1, idxFiles.length); + IIndexFile idxFile= idxFiles[0]; IIndexInclude[] includes= idxFile.getIncludes(); assertEquals(2, includes.length); assertTrue(includes[0].isActive()); assertTrue(includes[0].isResolved()); assertFalse(includes[1].isActive()); - assertTrue(includes[1].isResolved()); + // includes[1].isResolved()); May or may not be resolved. } finally { index.releaseReadLock(); } @@ -1658,11 +1666,11 @@ public class IndexBugsTests extends BaseTestCase { waitForIndexer(); fIndex.acquireReadLock(); try { - IIndexFile f= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(f1)); + IIndexFile f= getIndexFile(f1); IIndexInclude i= f.getIncludes()[0]; assertTrue(i.isResolvedByHeuristics()); - f= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(f2)); + f= getIndexFile(f2); i= f.getIncludes()[0]; assertFalse(i.isResolvedByHeuristics()); } finally { @@ -1683,7 +1691,7 @@ public class IndexBugsTests extends BaseTestCase { waitForIndexer(); fIndex.acquireReadLock(); try { - IIndexFile f= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(f1)); + IIndexFile f= getIndexFile(f1); IIndexInclude[] is= f.getIncludes(); assertFalse(is[0].isResolved()); assertTrue(is[1].isResolvedByHeuristics()); @@ -1702,12 +1710,12 @@ 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 @@ -2125,7 +2133,7 @@ public class IndexBugsTests extends BaseTestCase { IIndex index= indexManager.getIndex(fCProject); index.acquireReadLock(); try { - IIndexFile file= index.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(f)); + IIndexFile file= getIndexFile(index, f); // check order of includes IIndexInclude[] incs = file.getIncludes(); assertEquals(2, incs.length); @@ -2157,7 +2165,7 @@ public class IndexBugsTests extends BaseTestCase { IIndex index= indexManager.getIndex(fCProject); index.acquireReadLock(); try { - IIndexFile file= index.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(f)); + IIndexFile file= getIndexFile(index, f); int idx= testData.indexOf("f("); IIndexName[] names = file.findNames(idx, idx+1); assertEquals(1, names.length); @@ -2423,4 +2431,4 @@ public class IndexBugsTests extends BaseTestCase { index.releaseReadLock(); } } -}
\ No newline at end of file +} diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexIncludeTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexIncludeTest.java index 2fda9e95f00..d48ce0825b2 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexIncludeTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexIncludeTest.java @@ -7,6 +7,7 @@ * * Contributors: * Markus Schorn - initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.index.tests; @@ -64,6 +65,7 @@ public class IndexIncludeTest extends IndexTestBase { CoreModel.newIncludeEntry(fProject.getPath(), null, fProject.getResource().getLocation()) }; fProject.setRawPathEntries(entries, npm()); + IndexerPreferences.set(fProject.getProject(), IndexerPreferences.KEY_INDEX_UNUSED_HEADERS_WITH_DEFAULT_LANG, "false"); } fIndex= CCorePlugin.getIndexManager().getIndex(fProject); } @@ -114,17 +116,16 @@ public class IndexIncludeTest extends IndexTestBase { ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() { public void run(IProgressMonitor monitor) throws CoreException { - file.setContents(new ByteArrayInputStream( "int included; int CONTEXT;\n".getBytes()), false, false, npm()); - file.setLocalTimeStamp(timestamp+1000); + file.setContents(new ByteArrayInputStream("int included; int CONTEXT;\n".getBytes()), false, false, npm()); + file.setLocalTimeStamp(timestamp + 1000); } }, npm()); assertTrue("Timestamp was not increased", file.getLocalTimeStamp() >= timestamp); TestSourceReader.waitUntilFileIsIndexed(fIndex, file, 4000); fIndex.acquireReadLock(); try { - IIndexFile ifile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(file)); - assertNotNull("Can't find " + file.getLocation(), ifile); - assertTrue("timestamp not ok", ifile.getTimestamp() >= timestamp); + IIndexFile ifile= getIndexFile(file); + assertTrue("Timestamp not ok", ifile.getTimestamp() >= timestamp); IIndexBinding[] result= fIndex.findBindings(Pattern.compile("testInclude_cpp"), true, IndexFilter.ALL, npm()); assertEquals(1, result.length); @@ -134,6 +135,13 @@ public class IndexIncludeTest extends IndexTestBase { } finally { fIndex.releaseReadLock(); } + } + + private IIndexFile getIndexFile(IFile file) throws CoreException { + IIndexFile[] files = fIndex.getFiles(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(file)); + assertTrue("Can't find " + file.getLocation(), files.length > 0); + assertEquals("Found " + files.length + " files for " + file.getLocation() + " instead of one", 1, files.length); + return files[0]; } // {source20061107} @@ -150,8 +158,7 @@ public class IndexIncludeTest extends IndexTestBase { fIndex.acquireReadLock(); try { - IIndexFile ifile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(file)); - assertNotNull(ifile); + IIndexFile ifile= getIndexFile(file); IIndexInclude[] includes= ifile.getIncludes(); assertEquals(2, includes.length); @@ -174,8 +181,7 @@ public class IndexIncludeTest extends IndexTestBase { fIndex.acquireReadLock(); try { - IIndexFile ifile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(file)); - assertNotNull(ifile); + IIndexFile ifile= getIndexFile(file); IIndexInclude[] includes= ifile.getIncludes(); assertEquals(1, includes.length); @@ -194,8 +200,7 @@ public class IndexIncludeTest extends IndexTestBase { fIndex.acquireReadLock(); try { - IIndexFile ifile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(file)); - assertNotNull(ifile); + IIndexFile ifile= getIndexFile(file); IIndexInclude[] includes= ifile.getIncludes(); assertEquals(1, includes.length); @@ -215,8 +220,7 @@ public class IndexIncludeTest extends IndexTestBase { fIndex.acquireReadLock(); try { - IIndexFile ifile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(file)); - assertNotNull(ifile); + IIndexFile ifile= getIndexFile(file); IIndexInclude[] includes= ifile.getIncludes(); assertEquals(1, includes.length); @@ -238,7 +242,10 @@ public class IndexIncludeTest extends IndexTestBase { public void testUpdateOfIncluded() throws Exception { String content1 = "int CONTEXT_20070404(x);\n"; String content2 = "int CONTEXT_20070404(y);\n"; - String content3 = "#define CONTEXT_20070404(x) ctx_20070404##x\n #include \"included_20070404.h\"\n int source_20070404;\n"; + String content3 = + "#define CONTEXT_20070404(x) ctx_20070404##x\n" + + "#include \"included_20070404.h\"\n" + + "int source_20070404;\n"; TestSourceReader.createFile(fProject.getProject(), "included_20070404.h", content1); TestSourceReader.createFile(fProject.getProject(), "notIncluded_20070404.h", "int notIncluded_20070404\n;"); TestSourceReader.createFile(fProject.getProject(), "includer_20070404.cpp", content3); @@ -332,8 +339,7 @@ public class IndexIncludeTest extends IndexTestBase { fIndex.acquireReadLock(); try { - IIndexFile ifile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(header)); - assertNotNull(ifile); + IIndexFile ifile= getIndexFile(header); IIndexInclude[] includes= fIndex.findIncludedBy(ifile); assertEquals(2, includes.length); @@ -352,8 +358,7 @@ public class IndexIncludeTest extends IndexTestBase { fIndex.acquireReadLock(); try { assertEquals(1, fIndex.findBindings("a20070426".toCharArray(), IndexFilter.ALL_DECLARED, npm()).length); - IIndexFile ifile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(header)); - assertNotNull(ifile); + IIndexFile ifile= getIndexFile(header); IIndexInclude[] includes= fIndex.findIncludedBy(ifile); assertEquals(2, includes.length); assertEquals(s1.getFullPath().toString(), includes[0].getIncludedByLocation().getFullPath()); @@ -370,8 +375,7 @@ public class IndexIncludeTest extends IndexTestBase { fIndex.acquireReadLock(); try { assertEquals(1, fIndex.findBindings("b20070426".toCharArray(), IndexFilter.ALL_DECLARED, npm()).length); - IIndexFile ifile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(header)); - assertNotNull(ifile); + IIndexFile ifile= getIndexFile(header); IIndexInclude[] includes= fIndex.findIncludedBy(ifile); assertEquals(2, includes.length); assertEquals(s1.getFullPath().toString(), includes[0].getIncludedByLocation().getFullPath()); @@ -448,14 +452,188 @@ public class IndexIncludeTest extends IndexTestBase { standardCheckUpdateIncludes(header, s1, "h20070427"); } + // #ifdef A + // static const int a = 0; + // #endif + // #ifdef B + // static const int b = 0; + // #endif + // #ifdef C + // static const int c = 0; + // #endif + + // #define A + // #include "h1.h" + // #undef A + // #define B + // #include "h1.h" + // #undef B + + // #define C + // #include "h1.h" + + // #include "h2.h" + public void testMultiVariantHeaderUpdate() throws Exception { + waitForIndexer(); + TestScannerProvider.sIncludes= new String[] { fProject.getProject().getLocation().toOSString() }; + StringBuilder[] contents= getContentsForTest(4); + final StringBuilder h1Contents = contents[0]; + final IFile h1= TestSourceReader.createFile(fProject.getProject(), "h1.h", h1Contents.toString()); + IFile h2= TestSourceReader.createFile(fProject.getProject(), "h2.h", contents[1].toString()); + IFile s1= TestSourceReader.createFile(fProject.getProject(), "s1.cpp", contents[2].toString()); + IFile s2= TestSourceReader.createFile(fProject.getProject(), "s2.cpp", contents[3].toString()); + TestSourceReader.waitUntilFileIsIndexed(fIndex, s1, INDEXER_WAIT_TIME); + TestSourceReader.waitUntilFileIsIndexed(fIndex, s2, INDEXER_WAIT_TIME); + + fIndex.acquireReadLock(); + try { + IIndexFile[] indexFiles = fIndex.getFiles(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(h1)); + assertEquals(3, indexFiles.length); + } finally { + fIndex.releaseReadLock(); + } + + final long timestamp= System.currentTimeMillis(); + while (true) { + int pos = h1Contents.indexOf("int"); + if (pos < 0) + break; + h1Contents.replace(pos, pos + "int".length(), "float"); + } + ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + h1.setContents(new ByteArrayInputStream(h1Contents.toString().getBytes()), false, false, npm()); + h1.setLocalTimeStamp(timestamp + 1000); + } + }, npm()); + waitForIndexer(); + + fIndex.acquireReadLock(); + try { + IIndexFile[] indexFiles = fIndex.getFiles(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(h1)); + assertEquals(3, indexFiles.length); + for (IIndexFile indexFile : indexFiles) { + assertTrue("Timestamp not ok", indexFile.getTimestamp() >= timestamp); + } + } finally { + fIndex.releaseReadLock(); + } + } + + // #ifdef A + // static const int a = 0; + // #endif + // #ifdef B + // static const int b = 0; + // #endif + // #ifdef C + // static const int c = 0; + // #endif + + // #define A + // #include "h1.h" + // #undef A + // #define B + // #include "h1.h" + // #undef B + + // #define C + // #include "h1.h" + + // #include "h2.h" + + // #ifndef H1_H_ + // #define H1_H_ + // #ifdef A + // static const int a = 0; + // #endif + // #ifdef B + // static const int b = 0; + // #endif + // #ifdef C + // static const int c = 0; + // #endif + // #endif // H1_H_ + public void testPragmaOnceChange() throws Exception { + waitForIndexer(); + TestScannerProvider.sIncludes= new String[] { fProject.getProject().getLocation().toOSString() }; + CharSequence[] contents= getContentsForTest(5); + final CharSequence h1Contents = contents[0]; + final IFile h1= TestSourceReader.createFile(fProject.getProject(), "h1.h", h1Contents.toString()); + IFile h2= TestSourceReader.createFile(fProject.getProject(), "h2.h", contents[1].toString()); + IFile s1= TestSourceReader.createFile(fProject.getProject(), "s1.cpp", contents[2].toString()); + IFile s2= TestSourceReader.createFile(fProject.getProject(), "s2.cpp", contents[3].toString()); + TestSourceReader.waitUntilFileIsIndexed(fIndex, s1, INDEXER_WAIT_TIME); + TestSourceReader.waitUntilFileIsIndexed(fIndex, s2, INDEXER_WAIT_TIME); + + fIndex.acquireReadLock(); + try { + IIndexFile[] indexFiles = fIndex.getFiles(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(h1)); + assertEquals(3, indexFiles.length); + for (IIndexFile indexFile : indexFiles) { + assertFalse(indexFile.hasPragmaOnceSemantics()); + assertEquals(1, fIndex.findIncludedBy(indexFile).length); + } + } finally { + fIndex.releaseReadLock(); + } + + // Change h1.h so that it has the pragma-once semantics. + final long t1= System.currentTimeMillis(); + final String changedContents = contents[4].toString(); + ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + h1.setContents(new ByteArrayInputStream(changedContents.getBytes()), false, false, npm()); + h1.setLocalTimeStamp(t1 + 1000); + } + }, npm()); + waitForIndexer(); + + fIndex.acquireReadLock(); + try { + IIndexFile[] indexFiles = fIndex.getFiles(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(h1)); + assertEquals(1, indexFiles.length); + for (IIndexFile indexFile : indexFiles) { + assertTrue("Timestamp not ok", indexFile.getTimestamp() >= t1); + assertTrue(indexFile.hasPragmaOnceSemantics()); + // Included twice by h2.h and once by s1.cpp + assertEquals(2, fIndex.findIncludedBy(indexFile).length); + } + } finally { + fIndex.releaseReadLock(); + } + + // Change h1.h back to the original state without the pragma-once semantics. + final long t2= System.currentTimeMillis(); + ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + h1.setContents(new ByteArrayInputStream(h1Contents.toString().getBytes()), false, false, npm()); + h1.setLocalTimeStamp(t2 + 2000); + } + }, npm()); + waitForIndexer(); + + fIndex.acquireReadLock(); + try { + IIndexFile[] indexFiles = fIndex.getFiles(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(h1)); + assertEquals(3, indexFiles.length); + for (IIndexFile indexFile : indexFiles) { + assertTrue("Timestamp not ok", indexFile.getTimestamp() >= t2); + assertFalse(indexFile.hasPragmaOnceSemantics()); + assertEquals(1, fIndex.findIncludedBy(indexFile).length); + } + } finally { + fIndex.releaseReadLock(); + } + } + private void standardCheckUpdateIncludes(IFile header, IFile s1, String tag) throws Exception { fIndex.acquireReadLock(); try { assertEquals(1, fIndex.findBindings(tag.toCharArray(), IndexFilter.ALL_DECLARED, npm()).length); - IIndexFile ifile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(header)); - IIndexFile sfile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(s1)); - assertNotNull(ifile); + IIndexFile ifile= getIndexFile(header); + IIndexFile sfile= getIndexFile(s1); IIndexInclude[] includes= fIndex.findIncludedBy(ifile); assertEquals(1, includes.length); assertEquals(s1.getFullPath().toString(), includes[0].getIncludedByLocation().getFullPath()); @@ -464,7 +642,6 @@ public class IndexIncludeTest extends IndexTestBase { assertTrue(includes[0].isResolved()); assertFalse(includes[0].isSystemInclude()); - assertNotNull(sfile); includes= fIndex.findIncludes(sfile); assertEquals(3, includes.length); assertEquals(header.getFullPath().toString(), includes[0].getIncludesLocation().getFullPath()); @@ -494,13 +671,11 @@ public class IndexIncludeTest extends IndexTestBase { try { assertEquals(1, fIndex.findBindings(tag.toCharArray(), IndexFilter.ALL_DECLARED, npm()).length); - IIndexFile ifile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(header)); - IIndexFile sfile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(s1)); - assertNotNull(ifile); + IIndexFile ifile= getIndexFile(header); + IIndexFile sfile= getIndexFile(s1); IIndexInclude[] includes= fIndex.findIncludedBy(ifile); assertEquals(0, includes.length); - assertNotNull(sfile); includes= fIndex.findIncludes(sfile); assertEquals(2, includes.length); @@ -525,9 +700,8 @@ public class IndexIncludeTest extends IndexTestBase { try { assertEquals(1, fIndex.findBindings(tag.toCharArray(), IndexFilter.ALL_DECLARED, npm()).length); - IIndexFile ifile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(header)); - IIndexFile sfile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(s1)); - assertNotNull(ifile); + IIndexFile ifile= getIndexFile(header); + IIndexFile sfile= getIndexFile(s1); IIndexInclude[] includes= fIndex.findIncludedBy(ifile); assertEquals(1, includes.length); assertEquals(s1.getFullPath().toString(), includes[0].getIncludedByLocation().getFullPath()); @@ -536,7 +710,6 @@ public class IndexIncludeTest extends IndexTestBase { assertTrue(includes[0].isResolved()); assertTrue(includes[0].isSystemInclude()); - assertNotNull(sfile); includes= fIndex.findIncludes(sfile); assertEquals(2, includes.length); assertEquals(header.getFullPath().toString(), includes[0].getIncludesLocation().getFullPath()); @@ -560,9 +733,8 @@ public class IndexIncludeTest extends IndexTestBase { try { assertEquals(1, fIndex.findBindings(tag.toCharArray(), IndexFilter.ALL_DECLARED, npm()).length); - IIndexFile ifile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(header)); - IIndexFile sfile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(s1)); - assertNotNull(ifile); + IIndexFile ifile= getIndexFile(header); + IIndexFile sfile= getIndexFile(s1); IIndexInclude[] includes= fIndex.findIncludedBy(ifile); assertEquals(1, includes.length); assertEquals(s1.getFullPath().toString(), includes[0].getIncludedByLocation().getFullPath()); @@ -571,7 +743,6 @@ public class IndexIncludeTest extends IndexTestBase { assertTrue(includes[0].isResolved()); assertFalse(includes[0].isSystemInclude()); - assertNotNull(sfile); includes= fIndex.findIncludes(sfile); assertEquals(2, includes.length); assertEquals(header.getFullPath().toString(), includes[0].getIncludesLocation().getFullPath()); diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexListenerTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexListenerTest.java index 8be862dd17c..89fdf310f66 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexListenerTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexListenerTest.java @@ -101,9 +101,11 @@ public class IndexListenerTest extends BaseTestCase { assertTrue(im.joinIndexer(10000, npm())); IIndexChangeListener listener = new IIndexChangeListener() { public void indexChanged(IIndexChangeEvent event) { - synchronized (mutex) { - projects.add(event.getAffectedProject()); - mutex.notify(); + if (!event.getFilesWritten().isEmpty()) { + synchronized (mutex) { + projects.add(event.getAffectedProject()); + mutex.notify(); + } } } }; @@ -119,7 +121,6 @@ public class IndexListenerTest extends BaseTestCase { assertTrue(projects.contains(fProject1)); projects.clear(); - IFile file1= TestSourceReader.createFile(fProject1.getProject(), "test.cpp", "int b;"); IFile file2= TestSourceReader.createFile(fProject2.getProject(), "test.cpp", "int c;"); synchronized (mutex) { diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexMultiVariantHeaderTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexMultiVariantHeaderTest.java new file mode 100644 index 00000000000..c798cdebc11 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexMultiVariantHeaderTest.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * 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.index.tests; + +import junit.framework.TestSuite; + +import org.eclipse.cdt.core.dom.ast.IFunction; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable; + +/** + * Tests for header files included in multiple variants. + * + * The first line of each comment section preceding a test contains the name of the file + * to put the contents of the section to. To request the AST of a file, put an asterisk after + * the file name. + */ +public class IndexMultiVariantHeaderTest extends IndexBindingResolutionTestBase { + + public IndexMultiVariantHeaderTest() { + setStrategy(new SinglePDOMTestNamedFilesStrategy(true)); + } + + public static TestSuite suite() { + return suite(IndexMultiVariantHeaderTest.class); + } + + // test.h + // #ifdef func + // #undef func + // #endif + // + // #define func(x) foo ## x + + // test.c * + // #include "test.h" + // + // void func(1)() {} + // + // #undef func + // #define func(x) bar ## x + // + // void func(2)() {} + // + // #include "test.h" + // void func(3)() {} + public void testExampleFromBug197989_Comment0() throws Exception { + IFunction f1 = getBindingFromASTName("func(1)", 7, IFunction.class); + assertEquals("foo1", f1.getName()); + IFunction f2 = getBindingFromASTName("func(2)", 7, IFunction.class); + assertEquals("bar2", f2.getName()); + IFunction f3 = getBindingFromASTName("func(3)", 7, IFunction.class); + assertEquals("foo3", f3.getName()); + } + + // stddef.h + // #if !defined(_STDDEF_H) || defined(__need_NULL) + // + // #if !defined(__need_NULL) + // #define _STDDEF_H + // #endif /* !defined(__need_NULL) */ + // + // #if defined(_STDDEF_H) || defined(__need_NULL) + // #define NULL 0 + // #endif /* defined(_STDDEF_H) || defined(__need_NULL) */ + // #undef __need_NULL + // + // #if defined(_STDDEF_H) + // typedef unsigned int size_t; + // #endif /* defined(_STDDEF_H) */ + // + // #endif /* !defined(_STDDEF_H) || defined(__need_NULL) */ + + // a.h + // #ifndef A_H_ + // #define A_H_ + // #include "stddef.h" + // #endif /* A_H_ */ + + // a.cpp * + // #define __need_NULL + // #include "stddef.h" + // void f1(char* p) {} + // void test() { + // f1(NULL); + // } + + // b.cpp + // #include "stddef.h" + // #include "a.h" + + // c.cpp * + // #include "a.h" + // void f2(char* p, size_t t) {} + // void test() { + // f2(NULL, 1); + // } + public void testExampleFromBug197989_Comment73() throws Exception { + getBindingFromASTName("f1(NULL)", 2, ICPPFunction.class); + getBindingFromASTName("f2(NULL, 1)", 2, ICPPFunction.class); + } + + // a.h + // external int X; + + // b.h + // #define X y + // #include "a.h" + // #undef X + // #define X z + // #include "a.h" + + // a.cpp * + // #define X x + // #include "a.h" + // static void test() { + // x = 0; + // } + + // b.cpp * + // #include "b.h" + // static void test() { + // y = 0; + // z = 0; + // } + public void _testSignificantMacroDetection() throws Exception { + // TODO(sprigogin): For this test to work REPORT_SIGNIFICANT_MACROS flag + // should be passed to CPreprocessor.expandMacro method. See + // http://bugs.eclipse.org/bugs/show_bug.cgi?id=197989#c92 for details. + getBindingFromASTName("x = 0", 1, ICPPVariable.class); + getBindingFromASTName("y = 0", 1, ICPPVariable.class); + getBindingFromASTName("z = 0", 1, ICPPVariable.class); + } +} diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java index 123318398e4..69ae8c4a08d 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java @@ -88,6 +88,13 @@ public class IndexNamesTests extends BaseTestCase { return result; } + private IIndexFile getIndexFile(int linkageID, IFile file) throws CoreException { + IIndexFile[] files = fIndex.getFiles(linkageID, IndexLocationFactory.getWorkspaceIFL(file)); + assertTrue("Can't find " + file.getLocation(), files.length > 0); + assertEquals("Found " + files.length + " files for " + file.getLocation() + " instead of one", 1, files.length); + return files[0]; + } + protected void waitUntilFileIsIndexed(IFile file, int time) throws Exception { TestSourceReader.waitUntilFileIsIndexed(fIndex, file, time); } @@ -263,7 +270,7 @@ public class IndexNamesTests extends BaseTestCase { fIndex.acquireReadLock(); try { - IIndexFile ifile= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(file)); + IIndexFile ifile= getIndexFile(ILinkage.CPP_LINKAGE_ID, file); IIndexName[] names= ifile.findNames(0, content.length()); int j= 0; for (IIndexName indexName : names) { @@ -321,7 +328,7 @@ public class IndexNamesTests extends BaseTestCase { CoreException { fIndex.acquireReadLock(); try { - IIndexFile ifile= fIndex.getFile(linkageID, IndexLocationFactory.getWorkspaceIFL(file)); + IIndexFile ifile= getIndexFile(linkageID, file); IIndexName[] names= ifile.findNames(0, Integer.MAX_VALUE); int j= 0; for (IIndexName indexName : names) { diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexTests.java index 6b3d23b37fd..97982030531 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexTests.java @@ -30,6 +30,7 @@ public class IndexTests extends TestSuite { suite.addTest(IndexNamesTests.suite()); suite.addTest(TeamSharedIndexTest.suite()); suite.addTest(IndexProviderManagerTest.suite()); + suite.addTest(IndexMultiVariantHeaderTest.suite()); IndexCPPBindingResolutionBugs.addTests(suite); IndexCPPBindingResolutionTest.addTests(suite); diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/DefDeclTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/DefDeclTests.java index 1a6929db213..da46316999e 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/DefDeclTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/DefDeclTests.java @@ -6,8 +6,8 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * QNX - Initial API and implementation - * Markus Schorn (Wind River Systems) + * QNX - Initial API and implementation + * Markus Schorn (Wind River Systems) *******************************************************************************/ package org.eclipse.cdt.internal.pdom.tests; @@ -183,6 +183,11 @@ public class DefDeclTests extends PDOMTestBase { checkReference(binding, "ref" + testNum, ref); } + private IIndexFile getSingleFile(IIndexFileLocation ifl) throws CoreException { + IIndexFile[] files= pdom.getFiles(ILinkage.C_LINKAGE_ID, ifl); + assertEquals(1, files.length); + return files[0]; + } /* ------------------ Tests Started Here ------------------------ */ public void testInit() { // will fail if setUp fails, maybe timelimit is too small for warm-up @@ -237,7 +242,7 @@ public class DefDeclTests extends PDOMTestBase { String elName = "foo" + "08"; IIndexFileLocation ifl= IndexLocationFactory.getIFL((ITranslationUnit) cproject.findElement(new Path("func.c"))); - IIndexFile file= pdom.getFile(ILinkage.C_LINKAGE_ID, ifl); + IIndexFile file= getSingleFile(ifl); int offset= TestSourceReader.indexOfInFile("foo08();", new Path(ifl.getFullPath())); IIndexName[] names= file.findNames(offset, 5); assertEquals(1, names.length); @@ -249,7 +254,7 @@ public class DefDeclTests extends PDOMTestBase { // check the other file ifl= IndexLocationFactory.getIFL((ITranslationUnit) cproject.findElement(new Path("second.c"))); - file= pdom.getFile(ILinkage.C_LINKAGE_ID, ifl); + file= getSingleFile(ifl); offset= TestSourceReader.indexOfInFile("foo08();", new Path(ifl.getFullPath())); names= file.findNames(offset, 5); assertEquals(1, names.length); diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/IncludesTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/IncludesTests.java index 5f72bcb7994..be8784315ae 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/IncludesTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/IncludesTests.java @@ -22,6 +22,7 @@ import org.eclipse.cdt.core.index.IndexLocationFactory; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.Path; /** @@ -47,26 +48,30 @@ public class IncludesTests extends PDOMTestBase { index.releaseReadLock(); } + private IIndexFile getIndexFile(IFile file) throws CoreException { + IIndexFile[] files = index.getFiles(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(file)); + assertTrue("Can't find " + file.getLocation(), files.length > 0); + assertEquals("Found " + files.length + " files for " + file.getLocation() + " instead of one", 1, files.length); + return files[0]; + } + public void testIncludedBy() throws Exception { IResource loc = project.getProject().findMember("I2.h"); - IIndexFile file = index.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL((IFile) loc)); - assertNotNull(file); + IIndexFile file = getIndexFile((IFile) loc); IIndexInclude[] allIncludedBy = index.findIncludedBy(file, -1); assertEquals(9, allIncludedBy.length); // i.e. all of them } - + public void testIncludes() throws Exception { IResource loc = project.getProject().findMember("I1.cpp"); - IIndexFile file = index.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL((IFile) loc)); - assertNotNull(file); + IIndexFile file = getIndexFile((IFile) loc); IIndexInclude[] allIncludesTo= index.findIncludes(file, -1); assertEquals(2, allIncludesTo.length); // i.e. I1.h, I2.h } public void testIncludeName() throws Exception { IResource loc = project.getProject().findMember("a/b/I6.h"); - IIndexFile file = index.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL((IFile) loc)); - assertNotNull(file); + IIndexFile file = getIndexFile((IFile) loc); IIndexInclude[] allIncludedBy = index.findIncludedBy(file, -1); assertEquals(2, allIncludedBy.length); for (IIndexInclude include : allIncludedBy) { 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 6718f076766..5c8ea899085 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 @@ -63,9 +63,10 @@ public class TestSourceReader { * @param srcRoot the directory inside the bundle containing the packages * @param clazz the name of the class containing the test * @param testName the name of the test - * @param sections the number of comment sections preceding the named test to return + * @param sections the number of comment sections preceding the named test to return. Pass zero + * to get all available sections. * @return an array of StringBuilder objects for each comment section found preceding the named - * test in the source code. + * test in the source code. * @throws IOException */ public static StringBuilder[] getContentsForTest(Bundle bundle, String srcRoot, Class clazz, @@ -100,7 +101,7 @@ public class TestSourceReader { } else { if (content.length() > 0) { contents.add(content); - if (contents.size() == sections + 1) + if (sections > 0 && contents.size() == sections + 1) contents.remove(0); content = new StringBuilder(); } @@ -285,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 { @@ -303,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..908aa8fdcaa 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 @@ -12,6 +12,7 @@ * Anton Leherbauer (Wind River Systems) * Warren Paul (Nokia) - Bug 218266 * James Blackburn (Broadcom Corp.) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.model; @@ -655,18 +656,26 @@ public class TranslationUnit extends Openable implements ITranslationUnit { } public boolean isHeaderUnit() { - return CCorePlugin.CONTENT_TYPE_CHEADER.equals(contentTypeId) - || CCorePlugin.CONTENT_TYPE_CXXHEADER.equals(contentTypeId); + return isHeaderContentType(contentTypeId); } public boolean isSourceUnit() { - if (isHeaderUnit()) + return isSourceContentType(contentTypeId); + } + + private static boolean isHeaderContentType(String contentType) { + return CCorePlugin.CONTENT_TYPE_CHEADER.equals(contentType) + || CCorePlugin.CONTENT_TYPE_CXXHEADER.equals(contentType); + } + + private static boolean isSourceContentType(String contentType) { + if (isHeaderContentType(contentType)) return false; - return CCorePlugin.CONTENT_TYPE_CSOURCE.equals(contentTypeId) - || CCorePlugin.CONTENT_TYPE_CXXSOURCE.equals(contentTypeId) - || CCorePlugin.CONTENT_TYPE_ASMSOURCE.equals(contentTypeId) - || LanguageManager.getInstance().isContributedContentType(contentTypeId); + return CCorePlugin.CONTENT_TYPE_CSOURCE.equals(contentType) + || CCorePlugin.CONTENT_TYPE_CXXSOURCE.equals(contentType) + || CCorePlugin.CONTENT_TYPE_ASMSOURCE.equals(contentType) + || LanguageManager.getInstance().isContributedContentType(contentType); } public boolean isCLanguage() { @@ -769,7 +778,10 @@ public class TranslationUnit extends Openable implements ITranslationUnit { } public IASTTranslationUnit getAST(IIndex index, int style, IProgressMonitor monitor) throws CoreException { - ITranslationUnit configureWith = getSourceContextTU(index, style); + IIndexFile[] contextToHeader = getContextToHeader(index, style); + ITranslationUnit configureWith = getConfigureWith(contextToHeader); + if (configureWith == this) + contextToHeader= null; IScannerInfo scanInfo= configureWith.getScannerInfo((style & AST_SKIP_IF_NO_BUILD_INFO) == 0); if (scanInfo == null) { @@ -786,7 +798,7 @@ public class TranslationUnit extends Openable implements ITranslationUnit { return null; } - IncludeFileContentProvider crf= getIncludeFileContentProvider(style, index, language.getLinkageID()); + IncludeFileContentProvider crf= getIncludeFileContentProvider(style, index, language.getLinkageID(), contextToHeader); int options= 0; if ((style & AST_SKIP_FUNCTION_BODIES) != 0) { options |= ILanguage.OPTION_SKIP_FUNCTION_BODIES; @@ -812,7 +824,7 @@ public class TranslationUnit extends Openable implements ITranslationUnit { return ast; } - private IncludeFileContentProvider getIncludeFileContentProvider(int style, IIndex index, int linkageID) { + private IncludeFileContentProvider getIncludeFileContentProvider(int style, IIndex index, int linkageID, IIndexFile[] contextToHeader) { final ICProject cprj= getCProject(); final ProjectIndexerInputAdapter pathResolver = new ProjectIndexerInputAdapter(cprj); IncludeFileContentProvider fileContentsProvider; @@ -825,9 +837,7 @@ public class TranslationUnit extends Openable implements ITranslationUnit { if (index != null && (style & AST_SKIP_INDEXED_HEADERS) != 0) { IndexBasedFileContentProvider ibcf= new IndexBasedFileContentProvider(index, pathResolver, linkageID, fileContentsProvider); - if ((style & AST_CONFIGURE_USING_SOURCE_CONTEXT) != 0) { - ibcf.setSupportFillGapFromContextToHeader(true); - } + ibcf.setContextToHeaderGap(contextToHeader); fileContentsProvider= ibcf; } @@ -839,52 +849,83 @@ public class TranslationUnit extends Openable implements ITranslationUnit { return fileContentsProvider; } - private static int[] CTX_LINKAGES= {ILinkage.CPP_LINKAGE_ID, ILinkage.C_LINKAGE_ID}; - public ITranslationUnit getSourceContextTU(IIndex index, int style) { + private static final int[] CTX_LINKAGES= { ILinkage.CPP_LINKAGE_ID, ILinkage.C_LINKAGE_ID }; + public IIndexFile[] getContextToHeader(IIndex index, int style) { if (index != null && (style & AST_CONFIGURE_USING_SOURCE_CONTEXT) != 0) { try { fLanguageOfContext= null; - for (int element : 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<IIndexFile> visited= new HashSet<IIndexFile>(); - 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; + final IIndexFileLocation ifl = IndexLocationFactory.getIFL(this); + if (ifl != null) { + IIndexFile best = null; + IIndexFile contextOfBest = null; + int bestScore= -1; + // Find file variant that has the most content and preferably was parsed in + // context of a source file. + for (int linkageID : CTX_LINKAGES) { + for (IIndexFile indexFile : index.getFiles(linkageID, ifl)) { + int score= indexFile.getMacros().length * 2; + IIndexFile context= getParsedInContext(indexFile); + if (isSourceFile(context)) + score++; + if (score > bestScore) { + bestScore= score; + best= indexFile; + contextOfBest = context; } } } + + if (best != null && contextOfBest != best) { + return new IIndexFile[] { contextOfBest, best }; + } } } catch (CoreException e) { CCorePlugin.log(e); } } - return this; + return null; } - private IIndexFile getParsedInContext(IIndexFile indexFile) - throws CoreException { - IIndexInclude include= indexFile.getParsedInContext(); - if (include != null) { - return include.getIncludedBy(); + private IIndexFile getParsedInContext(IIndexFile indexFile) throws CoreException { + HashSet<IIndexFile> visited= new HashSet<IIndexFile>(); + // Bug 199412, may recurse. + while (visited.add(indexFile)) { + IIndexInclude include= indexFile.getParsedInContext(); + if (include == null) + break; + indexFile = include.getIncludedBy(); } - return null; + return indexFile; + } + + /** + * Returns <code>true</code> if the given file was parsed in a context of a source file. + * @throws CoreException + */ + private boolean isSourceFile(IIndexFile indexFile) throws CoreException { + String path = indexFile.getLocation().getURI().getPath(); + IContentType cType = CCorePlugin.getContentType(getCProject().getProject(), path); + if (cType == null) + return false; + + return isSourceContentType(cType.getId()); + } + + private ITranslationUnit getConfigureWith(IIndexFile[] contextToHeader) throws CoreException { + if (contextToHeader != null) { + ITranslationUnit configureWith = CoreModelUtil.findTranslationUnitForLocation( + contextToHeader[0].getLocation(), getCProject()); + if (configureWith != null) + return configureWith; + } + return this; } public IASTCompletionNode getCompletionNode(IIndex index, int style, int offset) throws CoreException { - ITranslationUnit configureWith= getSourceContextTU(index, style); + IIndexFile[] contextToHeader = getContextToHeader(index, style); + ITranslationUnit configureWith = getConfigureWith(contextToHeader); + if (configureWith == this) + contextToHeader= null; IScannerInfo scanInfo = configureWith.getScannerInfo((style & ITranslationUnit.AST_SKIP_IF_NO_BUILD_INFO) == 0); if (scanInfo == null) { @@ -896,7 +937,7 @@ public class TranslationUnit extends Openable implements ITranslationUnit { ILanguage language= configureWith.getLanguage(); fLanguageOfContext= language; if (language != null) { - IncludeFileContentProvider crf= getIncludeFileContentProvider(style, index, language.getLinkageID()); + IncludeFileContentProvider crf= getIncludeFileContentProvider(style, index, language.getLinkageID(), contextToHeader); IASTCompletionNode result = language.getCompletionNode(fileContent, scanInfo, crf, index, ParserUtil.getParserLogService(), offset); if (result != null) { 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 <code>0</code> if not applicable */ public int getEndingLineNumber(); + + /** + * Returns the inclusion statement that included this file, or <code>null</code> for + * a top-level file. + * Also <code>null</code> 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..4cf5ca99645 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,22 @@ * 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; +import org.eclipse.cdt.core.index.IIndexFile; +import org.eclipse.cdt.core.parser.ISignificantMacros; + + /** * 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 { /** * <code>INCLUDE_NAME</code> describes the relationship between an include directive and * it's name. @@ -64,4 +66,33 @@ public interface IASTPreprocessorIncludeStatement extends * @since 5.1 */ public boolean isResolvedByHeuristics(); + + /** + * Returns the list of versions of the target file, each of which is + * identified by its significant macros, that had been included + * in this translation-unit prior to this statement. + * @noreference This method is not intended to be referenced by clients. + */ + public ISignificantMacros[] getLoadedVersions(); + + /** + * Returns a hash-code for the contents of the file included, or <code>0</code> + * if the content has not been parsed. + * @since 5.4 + */ + public long getContentsHash(); + + /** + * Returns true, if an attempt will be or has been made to create AST for the target + * of this inclusion. + * @since 5.4 + */ + public boolean createsAST(); + + /** + * Returns the file from the index that this include statement has pulled in, or <code>null</code> + * if the include creates AST or is unresolved or skipped. + * @since 5.4 + */ + public IIndexFile getImportedIndexFile(); } 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 { /** * <code>OWNED_DECLARATION</code> represents the relationship between an <code>IASTTranslationUnit</code> 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..28a91aa36d4 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IFileNomination.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * 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. + * <p> + * This method should only be called after the included file has been parsed. The method will + * return {@link ISignificantMacros#NONE}</code> 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; +} 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 - * <code>null</code> if the file was not indexed in this linkage. + * Returns the file object for the given location and linkage or <code>null</code> if the file + * was not indexed in this linkage. + * <p> + * 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 <code>null</code> * @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 <code>null</code>, 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 <code>null</code> 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 = {}; /** @@ -33,6 +36,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 * @throws CoreException @@ -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. - * <code>0</code> will be returned in case the hash-code is unknown. - * @return the hash-code of the scanner configuration or <code>0</code>. - * @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 <code>null</code>. */ IIndexInclude getParsedInContext() throws CoreException; - + + /** + * Returns <code>true</code> 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 @@ -324,6 +324,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. */ public final static int SYNTAX_ERROR = SYNTAX_RELATED | 0x001; 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..e4182f46133 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ISignificantMacros.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * 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); + } + + 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 <T> extends CharTable { + public static final CharArrayObjectMap<Object> EMPTY_MAP = new CharArrayObjectMap<Object>(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 <T> CharArrayObjectMap<T> emptyMap() { + return (CharArrayObjectMap<T>) 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<T> newTable = (CharArrayObjectMap<T>) 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(); + } + + 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 String getDeclaredInOneFileOnly(IBinding binding) { + 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..f6f48df2dda 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,9 @@ 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; + /** The semaphore controlling exclusive access to the AST. */ private final Semaphore fSemaphore= new Semaphore(1); @@ -367,6 +371,7 @@ public abstract class ASTTranslationUnit extends ASTNode implements IASTTranslat if (fIndexFileSet != null) { List<IIndexFile> files= fileContent.getFilesIncluded(); for (IIndexFile indexFile : files) { + fASTFileSet.remove(indexFile); fIndexFileSet.add(indexFile); } } @@ -376,13 +381,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 +456,25 @@ 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; + } + + public boolean hasPragmaOnceSemantics() { + return fPragmaOnceSemantics; + } + + public void setPragmaOnceSemantics(boolean value) { + assertNotFrozen(); + fPragmaOnceSemantics= value; + } + /** * 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<Object>()); + } + + private static ICPPClassType findBaseInstance(ICPPClassType a, ICPPClassTemplate pTemplate, int maxdepth, HashSet<Object> 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..fa011fc2c37 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<ISignificantMacros> handled = new HashSet<ISignificantMacros>(); + ArrayList<IIndexFragmentFile> result= new ArrayList<IIndexFragmentFile>(); + 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<FileContentKey> keys = new HashSet<FileContentKey>(); ArrayList<IIndexFragmentFile> result= new ArrayList<IIndexFragmentFile>(); - 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 { @@ -259,22 +295,25 @@ public class CIndex implements IIndex { public IIndexInclude[] findIncludedBy(IIndexFile file, int depth) throws CoreException { List<IIndexInclude> result= new ArrayList<IIndexInclude>(); - findIncludedBy(Collections.singletonList(file), result, depth, new HashSet<IIndexFileLocation>()); + findIncludedBy(file.getLinkageID(), Collections.singletonList(file), result, depth, + new HashSet<FileContentKey>()); return result.toArray(new IIndexInclude[result.size()]); } - public void findIncludedBy(List<IIndexFile> in, List<IIndexInclude> out, int depth, - HashSet<IIndexFileLocation> handled) throws CoreException { + public void findIncludedBy(int linkageID, List<IIndexFile> in, List<IIndexInclude> out, int depth, + HashSet<FileContentKey> handled) throws CoreException { List<IIndexFile> nextLevel= depth != 0 ? new LinkedList<IIndexFile>() : null; for (IIndexFile iIndexFile : in) { IIndexFragmentFile file = (IIndexFragmentFile) iIndexFile; for (int j = 0; j < fPrimaryFragmentCount; j++) { IIndexInclude[] includedBy= fFragments[j].findIncludedBy(file); for (IIndexInclude include : includedBy) { - if (handled.add(include.getIncludedByLocation())) { + final IIndexFile includer = include.getIncludedBy(); + FileContentKey key= new FileContentKey(linkageID, includer.getLocation(), includer.getSignificantMacros()); + if (handled.add(key)) { out.add(include); if (nextLevel != null) { - nextLevel.add(include.getIncludedBy()); + nextLevel.add(includer); } } } @@ -286,10 +325,9 @@ public class CIndex implements IIndex { if (depth > 0) { depth--; } - findIncludedBy(nextLevel, out, depth, handled); + findIncludedBy(linkageID, 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,15 +93,56 @@ public interface IIndexFragment { * May return <code>null</code>, 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. + * <p> + * 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 <code>null</code> 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 <code>null</code>, 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 <code>null</code> 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. + * <p> + * 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. * @param location the IIndexFileLocation representing the location of the file 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..210261583b7 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; @@ -34,17 +34,16 @@ public interface IIndexFragmentFile extends IIndexFile { void setContentsHash(long hash) throws CoreException; /** - * Sets the hash-code of the scanner configuration. + * Sets the hash-code of the file encoding. * @param hashcode a hash-code or <code>0</code> if it is unknown. - * @throws CoreException */ - void setScannerConfigurationHashcode(int hashcode) throws CoreException; + void setEncodingHashcode(int hashcode) throws CoreException; /** - * Sets the hash-code of the file encoding. - * @param hashcode a hash-code or <code>0</code> if it is unknown. + * 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 setEncodingHashcode(int hashcode) throws CoreException; + void setPragmaOnceSemantics(boolean value) throws CoreException; /** * Returns whether this file contains content in its @@ -56,4 +55,16 @@ public interface IIndexFragmentFile extends IIndexFile { * Returns the id of the linkage this file belongs to. */ int getLinkageID() throws CoreException; + + /** + * Changes the inclusions pointing to 'source' to point to this file, instead. + * The file 'source' must belong to the same fragment as this file. + */ + void transferIncluders(IIndexFragmentFile source) throws CoreException; + + /** + * Changes the inclusion from the context of 'source' to point to this file, instead. + * The file 'source' must belong to the same fragment as this file. + */ + void transferContext(IIndexFragmentFile source) throws CoreException; } 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 @@ -26,6 +26,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. */ boolean contains(IIndexFragmentFile file) throws CoreException; 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..b0833880aae 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,20 +6,19 @@ * 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; -import java.util.Collection; - import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; 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; @@ -33,10 +32,19 @@ import org.eclipse.core.runtime.CoreException; public interface IWritableIndex extends IIndex { static class IncludeInformation { - public IASTPreprocessorIncludeStatement fStatement; - public IIndexFileLocation fLocation; + public final IASTPreprocessorIncludeStatement fStatement; + public final IIndexFileLocation fLocation; + public final ISignificantMacros fSignificantMacros; + public final boolean fIsContext; public IIndexFragmentFile fTargetFile; - public boolean fIsContext= false; + + public IncludeInformation(IASTPreprocessorIncludeStatement stmt, + IIndexFileLocation location, ISignificantMacros sig, boolean isContext) { + fStatement= stmt; + fSignificantMacros= sig; + fLocation= location; + fIsContext= isContext; + } } /** @@ -45,14 +53,21 @@ 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 and linkage. This method + * returns file objects without content, also. + */ + IIndexFragmentFile[] getWritableFiles(int linkageID, IIndexFileLocation location) 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; @@ -62,21 +77,28 @@ public interface IWritableIndex extends IIndex { * @param a collection that receives IndexFileLocation objects for files that * had the cleared file as a context. May be <code>null</code>. */ - void clearFile(IIndexFragmentFile file, Collection<IIndexFileLocation> clearedContexts) throws CoreException; + void clearFile(IIndexFragmentFile file) throws CoreException; /** * 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 @@ -106,20 +128,20 @@ public interface IWritableIndex extends IIndex { /** * Acquires a write lock, while giving up a certain amount of read locks. */ - void acquireWriteLock(int giveupReadLockCount) throws InterruptedException; + void acquireWriteLock() throws InterruptedException; /** * Releases a write lock, reestablishing a certain amount of read locks. * Fully equivalent to <code>releaseWriteLock(int, true)</code>. */ - void releaseWriteLock(int establishReadLockCount); + void releaseWriteLock(); /** * Releases a write lock, reestablishing a certain amount of read locks. * @param establishReadLockCount amount of read-locks to establish. * @param flushDatabase when true the changes are flushed to disk. */ - void releaseWriteLock(int establishReadLockCount, boolean flushDatabase); + void releaseWriteLock(boolean flushDatabase); /** * Resets the counters for cache-hits @@ -156,4 +178,16 @@ public interface IWritableIndex extends IIndex { * Clears the result cache, caller needs to hold a write-lock. */ void clearResultCache(); + + /** + * Changes the inclusions pointing to 'source' to point to 'target', instead. + * Both files must belong to the writable fragment. + */ + void transferIncluders(IIndexFragmentFile source, IIndexFragmentFile target) throws CoreException; + + /** + * Changes the inclusion from the context of 'source' to point to 'target', instead. + * Both files must belong to the writable fragment. + */ + void transferContext(IIndexFragmentFile source, IIndexFragmentFile target) 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..0996a4ea8c9 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,18 +6,17 @@ * 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; -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; @@ -39,28 +38,32 @@ public interface IWritableIndexFragment extends IIndexFragment { * @param a collection that receives IndexFileLocation objects for files that * had the cleared file as a context. */ - void clearFile(IIndexFragmentFile file, Collection<IIndexFileLocation> contextsRemoved) throws CoreException; + void clearFile(IIndexFragmentFile file) throws CoreException; /** * 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..ccfc664eed6 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,21 @@ * 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.LinkedHashSet; 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,7 +33,9 @@ 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.FileVersion; import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContent.InclusionKind; import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContentProvider; import org.eclipse.cdt.internal.core.pdom.ASTFilePathResolver; @@ -37,8 +44,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 +52,14 @@ public final class IndexBasedFileContentProvider extends InternalFileContentProv private final IIndex fIndex; private int fLinkage; - private Set<IIndexFileLocation> fIncludedFiles= new HashSet<IIndexFileLocation>(); /** 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 long fFileSizeLimit= 0; - + private IIndexFile[] fContextToHeaderGap; + private final Map<IIndexFileLocation, IFileNomination> fPragmaOnce= new HashMap<IIndexFileLocation, IFileNomination>(); + public IndexBasedFileContentProvider(IIndex index, ASTFilePathResolver pathResolver, int linkage, IncludeFileContentProvider fallbackFactory) { this(index, pathResolver, linkage, fallbackFactory, null); @@ -68,8 +74,8 @@ public final class IndexBasedFileContentProvider extends InternalFileContentProv fLinkage= linkage; } - public void setSupportFillGapFromContextToHeader(boolean val) { - fSupportFillGapFromContextToHeader= val; + public void setContextToHeaderGap(IIndexFile[] ctxToHeader) { + fContextToHeaderGap= ctxToHeader; } public void setFileSizeLimit(long limit) { @@ -79,60 +85,63 @@ public final class IndexBasedFileContentProvider extends InternalFileContentProv public void setLinkage(int linkageID) { fLinkage= linkageID; } - - public void cleanupAfterTranslationUnit() { - fIncludedFiles.clear(); - } @Override - public boolean getInclusionExists(String path) { - return fPathResolver.doesIncludeFileExist(path); + public void resetForTranslationUnit() { + super.resetForTranslationUnit(); + fPragmaOnce.clear(); } - + + /** + * Reports detection of pragma once semantics. + */ @Override - public void reportTranslationUnitFile(String path) { - IIndexFileLocation ifl= fPathResolver.resolveASTPath(path); - fIncludedFiles.add(ifl); + 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 Boolean hasFileBeenIncludedInCurrentTranslationUnit(String path) { - IIndexFileLocation ifl= fPathResolver.resolveASTPath(path); - return fIncludedFiles.contains(ifl); + public IFileNomination isIncludedWithPragmaOnceSemantics(String filePath) { + return fPragmaOnce.get(fPathResolver.resolveIncludeFile(filePath)); + } + + @Override + public boolean getInclusionExists(String path) { + return fPathResolver.doesIncludeFileExist(path); } + @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<IIndexFile> files= new ArrayList<IIndexFile>(); List<IIndexMacro> macros= new ArrayList<IIndexMacro>(); List<ICPPUsingDirective> directives= new ArrayList<ICPPUsingDirective>(); - Set<IIndexFileLocation> ifls= new HashSet<IIndexFileLocation>(); - 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<IIndexFileLocation, IFileNomination> newPragmaOnce= new HashMap<IIndexFileLocation, IFileNomination>(); + LinkedHashSet<IIndexFile> preLoaded= new LinkedHashSet<IIndexFile>(); + collectFileContent(file, null, newPragmaOnce, preLoaded, files, macros, directives, null); + // Report pragma once inclusions, only if no exception was thrown. + fPragmaOnce.putAll(newPragmaOnce); + return new InternalFileContent(path, macros, directives, files, toList(preLoaded)); } 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); @@ -147,6 +156,26 @@ public final class IndexBasedFileContentProvider extends InternalFileContentProv return null; } + public List<String> toPathList(Collection<IIndexFileLocation> newPragmaOnce) { + List<String> newPragmaOncePaths= new ArrayList<String>(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,145 +184,122 @@ public final class IndexBasedFileContentProvider extends InternalFileContentProv return null; } - private void collectFileContent(IIndexFile file, Set<IIndexFileLocation> ifls, List<IIndexFile> files, - List<IIndexMacro> macros, List<ICPPUsingDirective> usingDirectives, boolean checkIncluded) - throws CoreException, NeedToParseException { + private boolean collectFileContent(IIndexFile file, IIndexFile stopAt, + Map<IIndexFileLocation, IFileNomination> newPragmaOnce, + LinkedHashSet<IIndexFile> preLoaded, List<IIndexFile> files, + List<IIndexMacro> macros, List<ICPPUsingDirective> usingDirectives, + Set<IIndexFile> preventRecursion) throws CoreException, NeedToParseException { + if (file.equals(stopAt)) + return true; + IIndexFileLocation ifl= file.getLocation(); - if (!ifls.add(ifl) || (checkIncluded && fIncludedFiles.contains(ifl))) { - return; + if (newPragmaOnce.containsKey(ifl)) + return false; + if (file.hasPragmaOnceSemantics()) + newPragmaOnce.put(ifl, file); + + if (preventRecursion != null) { + if (fPragmaOnce.containsKey(ifl)) + return false; + } else { + preventRecursion= new HashSet<IIndexFile>(); } - IndexFileContent content; + if (!preventRecursion.add(file)) + return false; + + final ICPPUsingDirective[] uds; + final Object[] pds; if (fRelatedIndexerTask != null) { - content= fRelatedIndexerTask.getFileContent(fLinkage, ifl); - if (content == null) { + IndexFileContent content= fRelatedIndexerTask.getFileContent(fLinkage, ifl, file); + if (content == null) throw new NeedToParseException(); - } + uds= content.getUsingDirectives(); + pds= content.getPreprocessingDirectives(); } else { - content= new IndexFileContent(); - content.setPreprocessorDirectives(file.getIncludes(), file.getMacros()); - content.setUsingDirectives(file.getUsingDirectives()); + 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) { + if (!file.hasPragmaOnceSemantics()) { + preLoaded.add(file); + } + 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, preLoaded, 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) { - if (!fSupportFillGapFromContextToHeader) { - return null; - } - - IIndexFileLocation ifl= fPathResolver.resolveASTPath(path); - if (ifl == null) { + public InternalFileContent getContentForContextToHeaderGap(String path, + IMacroDictionary macroDictionary) { + if (fContextToHeaderGap == null) { return null; } try { - IIndexFile targetFile= fIndex.getFile(fLinkage, ifl); - if (targetFile == null) { - return null; - } - - IIndexFile contextFile= findContext(targetFile); - if (contextFile == targetFile || contextFile == null) { + IIndexFile contextFile= fContextToHeaderGap[0]; + IIndexFile targetFile = fContextToHeaderGap[1]; + if (contextFile == null || targetFile == null || contextFile == targetFile) return null; - } - - HashSet<IIndexFile> filesIncluded= new HashSet<IIndexFile>(); + + Map<IIndexFileLocation, IFileNomination> newPragmaOnce= new HashMap<IIndexFileLocation, IFileNomination>(); + List<IIndexFile> filesIncluded= new ArrayList<IIndexFile>(); ArrayList<IIndexMacro> macros= new ArrayList<IIndexMacro>(); ArrayList<ICPPUsingDirective> directives= new ArrayList<ICPPUsingDirective>(); - if (!collectFileContentForGap(contextFile, ifl, filesIncluded, macros, directives)) { + LinkedHashSet<IIndexFile> preLoaded= new LinkedHashSet<IIndexFile>(); + try { + if (!collectFileContent(contextFile, targetFile, newPragmaOnce, preLoaded, + filesIncluded, macros, directives, new HashSet<IIndexFile>())) { + 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<IIndexFile>(filesIncluded)); + // Report pragma once inclusions. + fPragmaOnce.putAll(newPragmaOnce); + return new InternalFileContent(GAP, macros, directives, filesIncluded, toList(preLoaded)); } catch (CoreException e) { CCorePlugin.log(e); } return null; } - private IIndexFile findContext(IIndexFile file) throws CoreException { - final HashSet<IIndexFile> ifiles= new HashSet<IIndexFile>(); - ifiles.add(file); - IIndexInclude include= file.getParsedInContext(); - while (include != null) { - final IIndexFile context= include.getIncludedBy(); - if (!ifiles.add(context)) { - return file; - } - file= context; - include= context.getParsedInContext(); - } - return file; - } - - private boolean collectFileContentForGap(IIndexFile from, IIndexFileLocation to, - Set<IIndexFile> filesIncluded, List<IIndexMacro> macros, - List<ICPPUsingDirective> directives) throws CoreException { - final IIndexFileLocation ifl= from.getLocation(); - if (ifl.equals(to)) { - return true; + private List<FileVersion> toList(LinkedHashSet<IIndexFile> preLoaded) throws CoreException { + List<FileVersion> result= new ArrayList<InternalFileContent.FileVersion>(preLoaded.size()); + for (IIndexFile file : preLoaded) { + String path= fPathResolver.getASTPath(file.getLocation()); + result.add(new FileVersion(path, file.getSignificantMacros())); } - - 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; + return result; } - 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..0a0526da2c5 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 @@ -12,12 +12,11 @@ *******************************************************************************/ package org.eclipse.cdt.internal.core.index; -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.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 +42,27 @@ 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(int linkageID, IIndexFileLocation location) throws CoreException { + return fWritableFragment.getFiles(linkageID, location); + } + 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 +84,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.fSignificantMacros); } } ((IWritableIndexFragment) indexFragment).addFileContent(file, includes, macros, names, resolver, lock); @@ -96,12 +103,12 @@ public class WritableCIndex extends CIndex implements IWritableIndex { isWritableFragment(((IIndexFragmentFile)file).getIndexFragment()); } - public void clearFile(IIndexFragmentFile file, Collection<IIndexFileLocation> clearedContexts) throws CoreException { + public void clearFile(IIndexFragmentFile file) throws CoreException { IIndexFragment indexFragment = file.getIndexFragment(); if (!isWritableFragment(indexFragment)) { assert false : "Attempt to clear file of read-only fragment"; //$NON-NLS-1$ } else { - ((IWritableIndexFragment) indexFragment).clearFile(file, clearedContexts); + ((IWritableIndexFragment) indexFragment).clearFile(file); } } @@ -121,25 +128,25 @@ public class WritableCIndex extends CIndex implements IWritableIndex { fThread= null; } - public void acquireWriteLock(int giveupReadlockCount) throws InterruptedException { + public void acquireWriteLock() throws InterruptedException { checkThread(); assert !fIsWriteLocked: "Multiple write locks is not allowed"; //$NON-NLS-1$ - assert giveupReadlockCount == getReadLockCount(): "Unexpected read lock is not allowed"; //$NON-NLS-1$ - fWritableFragment.acquireWriteLock(giveupReadlockCount); + fWritableFragment.acquireWriteLock(getReadLockCount()); fIsWriteLocked= true; } - public void releaseWriteLock(int establishReadlockCount) { - releaseWriteLock(establishReadlockCount, true); + public void releaseWriteLock() { + releaseWriteLock(true); } - public void releaseWriteLock(int establishReadlockCount, boolean flush) { + public void releaseWriteLock(boolean flush) { checkThread(); assert fIsWriteLocked: "No write lock to be released"; //$NON-NLS-1$ - assert establishReadlockCount == getReadLockCount(): "Unexpected read lock is not allowed"; //$NON-NLS-1$ + // Bug 297641: Result cache of read only providers needs to be cleared. + int establishReadlockCount = getReadLockCount(); if (establishReadlockCount == 0) { clearResultCache(); } @@ -171,10 +178,23 @@ public class WritableCIndex extends CIndex implements IWritableIndex { fWritableFragment.flush(); } - /* (non-Javadoc) - * @see org.eclipse.cdt.internal.core.index.IWritableIndex#getDatabaseSizeBytes() - */ public long getDatabaseSizeBytes() { return fWritableFragment.getDatabaseSizeBytes(); } + + public void transferIncluders(IIndexFragmentFile source, IIndexFragmentFile target) throws CoreException { + if (source == null || target == null || !isWritableFile(source) || !isWritableFile(target)) + throw new IllegalArgumentException(); + if (source.equals(target)) + return; + target.transferIncluders(source); + } + + public void transferContext(IIndexFragmentFile source, IIndexFragmentFile target) throws CoreException { + if (source == null || target == null || !isWritableFile(source) || !isWritableFile(target)) + throw new IllegalArgumentException(); + if (source.equals(target)) + return; + target.transferContext(source); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/indexer/StandaloneIndexer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/indexer/StandaloneIndexer.java index dc38809eb7d..5203d4d7041 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/indexer/StandaloneIndexer.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/indexer/StandaloneIndexer.java @@ -358,12 +358,12 @@ public abstract class StandaloneIndexer { private void clearIndex() throws CoreException, InterruptedException { IWritableIndex index= getIndex(); // First clear the pdom - index.acquireWriteLock(0); + index.acquireWriteLock(); try { index.clear(); } finally { - index.releaseWriteLock(0); + index.releaseWriteLock(); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/indexer/StandaloneIndexerTask.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/indexer/StandaloneIndexerTask.java index 082e4da6785..8cb4e0b6734 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/indexer/StandaloneIndexerTask.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/indexer/StandaloneIndexerTask.java @@ -15,13 +15,8 @@ import java.text.NumberFormat; import java.util.Collection; import java.util.Iterator; -import com.ibm.icu.text.MessageFormat; - import org.eclipse.cdt.core.dom.ILinkage; -import org.eclipse.cdt.core.model.AbstractLanguage; -import org.eclipse.cdt.core.model.ILanguage; import org.eclipse.cdt.core.parser.IParserLogService; -import org.eclipse.cdt.core.parser.IScannerInfo; import org.eclipse.cdt.internal.core.index.IWritableIndex; import org.eclipse.cdt.internal.core.pdom.AbstractIndexerTask; import org.eclipse.cdt.internal.core.pdom.IndexerProgress; @@ -29,6 +24,8 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; +import com.ibm.icu.text.MessageFormat; + /** * A task for index updates. * @@ -112,15 +109,6 @@ public abstract class StandaloneIndexerTask extends AbstractIndexerTask { } @Override - final protected AbstractLanguage[] getLanguages(String filename) { - ILanguage l = fIndexer.getLanguageMapper().getLanguage(filename); - if (l instanceof AbstractLanguage) { - return new AbstractLanguage[] {(AbstractLanguage) l}; - } - return new AbstractLanguage[0]; - } - - @Override protected final IWritableIndex createIndex() { return fIndexer.getIndex(); } @@ -249,20 +237,6 @@ public abstract class StandaloneIndexerTask extends AbstractIndexerTask { protected void logException(Throwable e) { trace(e.getMessage()); } - - @SuppressWarnings("deprecation") - @Override - protected IScannerInfo createDefaultScannerConfig(int linkageID) { - IStandaloneScannerInfoProvider provider = fIndexer.getScannerInfoProvider(); - if(provider != null) - return provider.getDefaultScannerInformation(linkageID); - - IScannerInfo scannerInfo = fIndexer.getScannerInfo(); - if(scannerInfo != null) - return scannerInfo; - - return super.createDefaultScannerConfig(linkageID); - } /* (non-Javadoc) * @see org.eclipse.cdt.internal.core.pdom.AbstractIndexerTask#getLinkagesToParse() 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..314e83a5751 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,15 @@ 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.index.IIndexFile; +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 +192,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) { @@ -253,21 +257,33 @@ class ASTPragmaOperator extends ASTPragma { } class ASTInclusionStatement extends ASTPreprocessorNode implements IASTPreprocessorIncludeStatement { + private static final ISignificantMacros[] NO_VERSIONS = {}; + private final ASTPreprocessorName fName; private final String fPath; private final boolean fIsResolved; private final boolean fIsSystemInclude; private final boolean fFoundByHeuristics; + private final IFileNomination fNominationDelegate; + private boolean fPragmaOnce; + private boolean fCreatesAST; + private ISignificantMacros fSignificantMacros; + private ISignificantMacros[] fLoadedVersions = NO_VERSIONS; + private long fContentsHash; 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 +314,69 @@ 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; + } + + public void setLoadedVersions(ISignificantMacros[] versions) { + fLoadedVersions= versions; + } + + public ISignificantMacros[] getLoadedVersions() { + return fLoadedVersions; + } + + public long getContentsHash() { + if (fNominationDelegate != null) { + return 0; + } + return fContentsHash; + } + + public void setContentsHash(long hash) { + assert fNominationDelegate == null; + fCreatesAST= true; + fContentsHash= hash; + } + + public boolean createsAST() { + return fCreatesAST; + } + + public IIndexFile getImportedIndexFile() { + if (fNominationDelegate instanceof IIndexFile) + return (IIndexFile) fNominationDelegate; + + return null; + } } class ASTMacroDefinition extends ASTPreprocessorNode implements IASTPreprocessorObjectStyleMacroDefinition { @@ -579,6 +658,10 @@ class ASTFileLocation implements IASTFileLocation { public LocationCtxFile getLocationContext() { return fLocationCtx; } + + public IASTPreprocessorIncludeStatement getContextInclusionStatement() { + return fLocationCtx.getInclusionStatement(); + } } class ASTMacroExpansion extends ASTPreprocessorNode implements IASTPreprocessorMacroExpansion { @@ -708,6 +791,10 @@ class ASTFileLocationForBuiltins implements IASTFileLocation { public int getStartingLineNumber() { return 0; } + + public IASTPreprocessorIncludeStatement getContextInclusionStatement() { + return null; + } } @@ -723,4 +810,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..3b3eeb9d3c4 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; @@ -42,16 +48,21 @@ import org.eclipse.cdt.core.parser.ParseError; import org.eclipse.cdt.core.parser.ParserLanguage; import org.eclipse.cdt.core.parser.util.CharArrayIntMap; import org.eclipse.cdt.core.parser.util.CharArrayMap; +import org.eclipse.cdt.core.parser.util.CharArrayObjectMap; +import org.eclipse.cdt.core.parser.util.CharArraySet; 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.FileVersion; import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContent.InclusionKind; import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions; import org.eclipse.cdt.internal.core.parser.scanner.MacroDefinitionParser.InvalidMacroDefinitionException; 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 +99,42 @@ 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; + static final int NO_EXPANSION = 0x01; + static final int PROTECT_DEFINED = 0x02; + static final int STOP_AT_NL = 0x04; + static final int CHECK_NUMBERS = 0x08; + static final int REPORT_SIGNIFICANT_MACROS = 0x10; + static final int IGNORE_UNDEFINED_SIGNIFICANT_MACROS = 0x20; + + 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); + } + } private interface IIncludeFileTester<T> { T checkFile(String path, boolean isHeuristicMatch, IncludeSearchPathElement onPath); @@ -100,7 +142,13 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { final private IIncludeFileTester<InternalFileContent> createCodeReaderTester= new IIncludeFileTester<InternalFileContent>() { 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); + } 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,10 +232,9 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { // state information private final CharArrayMap<PreprocessorMacro> fMacroDictionary = new CharArrayMap<PreprocessorMacro>(512); + private final IMacroDictionary fMacroDictionaryFacade = new MacroDictionary(); private final LocationMap fLocationMap; - - /** Set of already included files */ - private final HashSet<String> fAllIncludedFiles= new HashSet<String>(); + private CharArraySet fPreventInclusion= new CharArraySet(0); private final Lexer fRootLexer; private final ScannerContext fRootContext; @@ -200,6 +247,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<String> fTracedGuards; + public CPreprocessor(FileContent fileContent, IScannerInfo info, ParserLanguage language, IParserLogService log, IScannerExtensionConfiguration configuration, @@ -217,7 +270,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 +292,38 @@ 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); if (info instanceof IExtendedScannerInfo) { final IExtendedScannerInfo einfo= (IExtendedScannerInfo) info; - fPreIncludedFiles= new String[][] {einfo.getMacroFiles(), einfo.getIncludeFiles()}; + fPreIncludedFiles= new String[][] { einfo.getMacroFiles(), einfo.getIncludeFiles() }; } + fFileContentProvider.resetForTranslationUnit(); } + + 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.setPragmaOnce(true); + return guard; + } else { + ctx.trackSignificantMacros(); + } + if (ctx != fRootContext) { + if (fLog.isTracing(TRACE_NO_GUARD)) { + if (fTracedGuards == null) + fTracedGuards= new HashSet<String>(); + 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; } @@ -371,15 +445,19 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { private void beforeFirstFetchToken() { if (fPreIncludedFiles != null) { - handlePreIncludedFiles(); - } - final String location = fLocationMap.getTranslationUnitPath(); - InternalFileContent content= fFileContentProvider.getContentForContextToHeaderGap(location); + handlePreIncludedFiles(); + fPreIncludedFiles= null; + } + final String location = fLocationMap.getTranslationUnitPath(); + InternalFileContent content= fFileContentProvider.getContentForContextToHeaderGap(location, + fMacroDictionaryFacade); if (content != null && content.getKind() == InclusionKind.FOUND_IN_INDEX) { - processInclusionFromIndex(0, location, content); + processInclusionFromIndex(0, location, content, false); } - fLocationMap.replacingFile(fFileContentProvider, fRootContent); - fRootContent= null; + + detectIncludeGuard(location, fRootContent.getSource(), fRootContext); + fLocationMap.parsingFile(fFileContentProvider, fRootContent); + fRootContent= null; } private void handlePreIncludedFiles() { @@ -726,11 +804,23 @@ 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(); + + final ILocationCtx locationCtx = fCurrentContext.getLocationCtx(); + ASTInclusionStatement inc = locationCtx.getInclusionStatement(); + if (inc != null) { + completeInclusion(inc); + } fLocationMap.popContext(locationCtx); - fCurrentContext= fCurrentContext.getParent(); + + fCurrentContext.propagateSignificantMacros(); + fCurrentContext= fCurrentContext.getParent(); assert fCurrentContext != null; ppToken= fCurrentContext.currentLexerToken(); @@ -781,7 +871,21 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { } } - private void checkNumber(Token number, final boolean isFloat) { + private void completeInclusion(ASTInclusionStatement inc) { + final ISignificantMacros sig; + CharArrayObjectMap<char[]> sigMacros= fCurrentContext.getSignificantMacros(); + if (sigMacros == null || sigMacros.isEmpty()) { + sig = ISignificantMacros.NONE; + } else { + sig = new SignificantMacros(sigMacros); + } + inc.setSignificantMacros(sig); + if (!inc.hasPragmaOnceSemantics()) { + fFileContentProvider.addLoadedVersions(inc.getPath(), fCurrentContext.getLoadedVersionCount(), sig); + } + } + + private void checkNumber(Token number, final boolean isFloat) { final char[] image= number.getCharImage(); boolean hasExponent = false; @@ -1151,7 +1255,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 +1265,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 +1284,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,71 +1363,129 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { } return; } - - String path= null; - boolean reported= false; - boolean isHeuristic= false; + + if (active && fCurrentContext.getDepth() == MAX_INCLUSION_DEPTH || fPreventInclusion.containsKey(headerName)) { + handleProblem(IProblem.PREPROCESSOR_EXCEEDS_MAXIMUM_INCLUSION_DEPTH, + lexer.getInputChars(poundOffset, condEndOffset), poundOffset, condEndOffset); + fPreventInclusion.put(headerName); + return; + } 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; - } - } else { - final InternalFileContent fi= findInclusion(includeDirective, userInclude, include_next, - getCurrentFilename(), createCodeReaderTester); - if (fi != null) { - path= fi.getFileLocation(); - isHeuristic= fi.isFoundByHeuristics(); - switch (fi.getKind()) { - case FOUND_IN_INDEX: - processInclusionFromIndex(poundOffset, path, fi); - break; - case USE_SOURCE: - AbstractCharArray source= fi.getSource(); - if (source != null && !isCircularInclusion(path)) { - 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)); - fctx.setFoundOnPath(fi.getFoundOnPath(), includeDirective); - fCurrentContext= fctx; + // Inactive include + String path= null; + boolean isHeuristic= false; + IFileNomination nominationDelegate= null; + + if (externGuard != null) { + // #ifndef GUARD + // #include "file.h" + // #endif + // 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; } - fLocationMap.replacingFile(fFileContentProvider, fi); - break; - - case SKIP_FILE: - break; } - } else { - final int len = headerName.length + 2; - StringBuilder name= new StringBuilder(len); - name.append(userInclude ? '"' : '<'); - name.append(headerName); - name.append(userInclude ? '"' : '>'); - - final char[] nameChars= new char[len]; - name.getChars(0, len, nameChars, 0); - handleProblem(IProblem.PREPROCESSOR_INCLUSION_NOT_FOUND, nameChars, poundOffset, condEndOffset); } + fLocationMap.encounterPoundInclude(poundOffset, nameOffsets[0], nameOffsets[1], + condEndOffset, headerName, path, userInclude, active, isHeuristic, nominationDelegate); + return; } - - if (!reported) { + + // Active include + final InternalFileContent fi= findInclusion(includeDirective, userInclude, include_next, + getCurrentFilename(), createCodeReaderTester); + if (fi == null) { + // Unresolved active include + final int len = headerName.length + 2; + StringBuilder name= new StringBuilder(len); + name.append(userInclude ? '"' : '<'); + name.append(headerName); + name.append(userInclude ? '"' : '>'); + + final char[] nameChars= new char[len]; + name.getChars(0, len, nameChars, 0); + handleProblem(IProblem.PREPROCESSOR_INCLUSION_NOT_FOUND, nameChars, poundOffset, condEndOffset); fLocationMap.encounterPoundInclude(poundOffset, nameOffsets[0], nameOffsets[1], - condEndOffset, headerName, path, userInclude, active, isHeuristic); + condEndOffset, headerName, null, userInclude, active, false, null); + return; + } + + // Resolved active include + final String path= fi.getFileLocation(); + final boolean isHeuristic= fi.isFoundByHeuristics(); + final boolean pragmaOnceContext= fCurrentContext.isPragmaOnce(); + + IFileNomination nominationDelegate= null; + ASTInclusionStatement stmt= null; + List<ISignificantMacros> loadedVerisons = null; + switch (fi.getKind()) { + case FOUND_IN_INDEX: + // Pulled in from index + nominationDelegate= fi.getFilesIncluded().get(0); + try { + ISignificantMacros sm = nominationDelegate.getSignificantMacros(); + fCurrentContext.addSignificantMacros(sm); + if (pragmaOnceContext && !nominationDelegate.hasPragmaOnceSemantics()) + loadedVerisons= fFileContentProvider.getLoadedVersions(path); + } catch (CoreException e) { + } + + processInclusionFromIndex(poundOffset, path, fi, true); + break; + case USE_SOURCE: + // Will be parsed + AbstractCharArray source= fi.getSource(); + if (source != null) { + 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)); + fctx.setFoundOnPath(fi.getFoundOnPath(), includeDirective); + detectIncludeGuard(path, source, fctx); + fCurrentContext= fctx; + stmt= ctx.getInclusionStatement(); + stmt.setContentsHash(source.getContentsHash()); + if (!fCurrentContext.isPragmaOnce()) { + // Track the loaded version count, even in a non-pragma-once context. + loadedVerisons= fFileContentProvider.getLoadedVersions(path); + fctx.setLoadedVersionCount(loadedVerisons.size()); + } + } + fLocationMap.parsingFile(fFileContentProvider, fi); + break; + + case SKIP_FILE: + // Already included or fast parsing mode. + break; + } + if (stmt == null) { + // Found in index or skipped. + stmt= fLocationMap.encounterPoundInclude(poundOffset, nameOffsets[0], nameOffsets[1], + condEndOffset, headerName, path, userInclude, active, isHeuristic, nominationDelegate); + } + // In a pragma once context store loaded versions of this non-pragma-once include + if (pragmaOnceContext && loadedVerisons != null && !loadedVerisons.isEmpty()) { + stmt.setLoadedVersions(loadedVerisons.toArray(new ISignificantMacros[loadedVerisons.size()])); } } - private void processInclusionFromIndex(int offset, String path, InternalFileContent fi) { + private void processInclusionFromIndex(int offset, String path, InternalFileContent fi, boolean updateContext) { List<IIndexMacro> mdefs= fi.getMacroDefinitions(); for (IIndexMacro macro : mdefs) { addMacroDefinition(macro); + if (updateContext) + fCurrentContext.internalModification(macro.getNameCharArray()); + } + for (FileVersion version : fi.getNonPragmaOnceVersions()) { + fFileContentProvider.addLoadedVersions(version.fPath, Integer.MAX_VALUE, version.fSigMacros); } fLocationMap.skippedFile(fLocationMap.getSequenceNumberForOffset(offset), fi); } @@ -1346,24 +1509,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 +1547,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 +1577,18 @@ 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) { + 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 +1605,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 +1621,11 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { int condEndOffset, endOffset; if (cond.canHaveActiveBranch(withinExpansion)) { + char[] macro= IncludeGuardDetection.detectIfNotDefinedIncludeEndif(lexer); + if (macro != null) { + fExternIncludeGuard= macro; + } + TokenList condition= new TokenList(); condEndOffset= getTokensWithinPPDirective(true, condition, withinExpansion); endOffset= lexer.currentToken().getEndOffset(); @@ -1469,6 +1637,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 +1707,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 +1721,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 +1814,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 && (options & IGNORE_UNDEFINED_SIGNIFICANT_MACROS) == 0) + fCurrentContext.significantMacroUndefined(name); return false; } boolean stopAtNewline= (options & STOP_AT_NL) != 0; @@ -1653,6 +1835,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { } } if (t.getType() != IToken.tLPAREN) { + if (reportSignificant) + fCurrentContext.significantMacro(macro); return false; } } @@ -1660,8 +1844,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { final ITokenSequence input= stopAtNewline ? fLineInputToMacroExpansion : fInputToMacroExpansion; final MacroExpander expander = withinExpansion ? new MacroExpander(this, fMacroDictionary, fLocationMap, fLexOptions) : fMacroExpander; - TokenList replacement= expander.expand(input, (options & PROTECT_DEFINED) != 0, macro, - identifier, contentAssist); + TokenList replacement= expander.expand(input, options, macro, identifier, contentAssist, fCurrentContext); final IASTName[] expansions= expander.clearImplicitExpansions(); final ImageLocationInfo[] ili= expander.clearImageLocationInfos(); final Token last= replacement.last(); @@ -1679,5 +1862,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/ILocationCtx.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ILocationCtx.java index ac52538bea4..2d9ac67ff07 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ILocationCtx.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ILocationCtx.java @@ -30,4 +30,8 @@ public interface ILocationCtx { */ ILocationCtx getParent(); + /** + * Returns inclusion statement that created this context, or <code>null</code>. + */ + ASTInclusionStatement getInclusionStatement(); } 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..56534886481 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 @@ -17,6 +17,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective; import org.eclipse.cdt.core.index.IIndexFile; import org.eclipse.cdt.core.index.IIndexMacro; import org.eclipse.cdt.core.parser.FileContent; +import org.eclipse.cdt.core.parser.ISignificantMacros; /** * Instructs the preprocessor on how to handle a file-inclusion. @@ -38,11 +39,21 @@ public class InternalFileContent extends FileContent { USE_SOURCE } + public static class FileVersion { + public final String fPath; + public final ISignificantMacros fSigMacros; + public FileVersion(String path, ISignificantMacros sig) { + fPath= path; + fSigMacros= sig; + } + } + private final InclusionKind fKind; private final AbstractCharArray fSource; private final List<IIndexMacro> fMacroDefinitions; private final List<ICPPUsingDirective> fUsingDirectives; private final String fFileLocation; + private final List<FileVersion> fNonPragmaOnceFiles; private boolean fHeuristic; private boolean fIsSource= false; private List<IIndexFile> fFiles; @@ -64,6 +75,7 @@ public class InternalFileContent extends FileContent { fMacroDefinitions= null; fUsingDirectives= null; fSource= null; + fNonPragmaOnceFiles= null; } /** @@ -79,6 +91,7 @@ public class InternalFileContent extends FileContent { fSource= content; fMacroDefinitions= null; fUsingDirectives= null; + fNonPragmaOnceFiles= null; if (fFileLocation == null) { throw new IllegalArgumentException(); } @@ -92,13 +105,14 @@ public class InternalFileContent extends FileContent { * @throws IllegalArgumentException in case the fileLocation or the macroDefinitions are <code>null</code>. */ public InternalFileContent(String fileLocation, List<IIndexMacro> macroDefinitions, List<ICPPUsingDirective> usingDirectives, - List<IIndexFile> files) { + List<IIndexFile> files, List<FileVersion> nonPragmaOnceVersions) { fKind= InclusionKind.FOUND_IN_INDEX; fFileLocation= fileLocation; fSource= null; fUsingDirectives= usingDirectives; fMacroDefinitions= macroDefinitions; fFiles= files; + fNonPragmaOnceFiles= nonPragmaOnceVersions; } /** @@ -155,6 +169,10 @@ public class InternalFileContent extends FileContent { public List<IIndexFile> getFilesIncluded() { return fFiles; } + + public List<FileVersion> getNonPragmaOnceVersions() { + return fNonPragmaOnceFiles; + } /** * Returns whether this inclusion was found by a heuristics. 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..82668c6293b 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,25 @@ * * 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.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +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.ISignificantMacros; 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 +33,25 @@ import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContent.Inclusio */ public abstract class InternalFileContentProvider extends IncludeFileContentProvider { private IIncludeFileResolutionHeuristics fIncludeResolutionHeuristics; + private final Map<String, IFileNomination> fPragmaOnce= new HashMap<String, IFileNomination>(); + private final Map<String, List<ISignificantMacros>> fLoadedVersions= new HashMap<String, List<ISignificantMacros>>(); /** - * 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 <code>null</code> 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 <code>null</code> 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 +62,38 @@ 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 <code>null</code> 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 resetForTranslationUnit() { + fPragmaOnce.clear(); + fLoadedVersions.clear(); + } + + /** + * Reports detection of pragma once semantics. */ - public void reportTranslationUnitFile(String filePath) { + public void reportPragmaOnceSemantics(String file, IFileNomination nomination) { + fPragmaOnce.put(file, nomination); } - + /** - * Returns whether or not the file has been included, or <code>null</code> if the content provider - * does not track that. + * Returns {@link IASTPreprocessorIncludeStatement} or {@link IIndexFile}, in + * case the file has been included using pragma once semantics, + * or <code>null</code> otherwise. */ - public Boolean hasFileBeenIncludedInCurrentTranslationUnit(String location) { - return null; + public IFileNomination isIncludedWithPragmaOnceSemantics(String filePath) { + return fPragmaOnce.get(filePath); } /** - * Returns a strategy for heuristically resolving includes, or <code>null</code> if this shall not - * be done. + * Returns a strategy for heuristically resolving includes, or <code>null</code> if this shall + * not be done. */ public final IIncludeFileResolutionHeuristics getIncludeHeuristics() { return fIncludeResolutionHeuristics; @@ -76,4 +102,26 @@ public abstract class InternalFileContentProvider extends IncludeFileContentProv public final void setIncludeResolutionHeuristics(IIncludeFileResolutionHeuristics heuristics) { fIncludeResolutionHeuristics= heuristics; } + + public List<ISignificantMacros> getLoadedVersions(String path) { + List<ISignificantMacros> result = fLoadedVersions.get(path); + return result == null ? Collections.<ISignificantMacros>emptyList() : result; + } + + public void addLoadedVersions(String path, int reduceVersions, ISignificantMacros sig) { + List<ISignificantMacros> list= fLoadedVersions.get(path); + if (list == null || reduceVersions == 0) { + fLoadedVersions.put(path, Collections.singletonList(sig)); + } else if (!list.contains(sig)) { + if (list.size() == 1) { + ISignificantMacros first = list.get(0); + list= new ArrayList<ISignificantMacros>(2); + list.add(first); + fLoadedVersions.put(path, list); + } else if (reduceVersions > 0 && reduceVersions < list.size()) { + list.subList(reduceVersions, list.size()).clear(); + } + list.add(sig); + } + } } 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/LocationCtxContainer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxContainer.java index 61e76bf99b5..bd4e98ad844 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxContainer.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxContainer.java @@ -259,4 +259,9 @@ class LocationCtxContainer extends LocationCtx { } return result; } + + @Override + public String toString() { + return "<synthetic>"; //$NON-NLS-1$ + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxFile.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxFile.java index 8964b2bf755..a33b6195dbc 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxFile.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxFile.java @@ -131,4 +131,9 @@ class LocationCtxFile extends LocationCtxContainer { public boolean isSourceFile() { return fIsSource; } + + @Override + public String toString() { + return fFilename; + } }
\ No newline at end of file diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxMacroExpansion.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxMacroExpansion.java index ed92105bffc..9e37e56a97f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxMacroExpansion.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxMacroExpansion.java @@ -105,4 +105,9 @@ class LocationCtxMacroExpansion extends LocationCtx { public ASTPreprocessorName[] getNestedMacroReferences() { return fLocationMap.getNestedMacroReferences((ASTMacroExpansion) fExpansionName.getParent()); } + + @Override + public String toString() { + return "Expansion of " + fExpansionName.toString(); //$NON-NLS-1$ + } } 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..1e849f2b4f5 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; @@ -226,14 +230,17 @@ public class LocationMap implements ILocationResolver { * @param userInclude <code>true</code> when specified with double-quotes. * @param active <code>true</code> 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) { + public ASTInclusionStatement encounterPoundInclude(int startOffset, int nameOffset, int nameEndOffset, int endOffset, + 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); + return inc; } public void encounteredComment(int offset, int endOffset, boolean isBlockComment) { @@ -743,10 +750,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<char[]> 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..9667a1ea3cc 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,8 @@ public class MacroExpander { private String fFixedCurrentFilename; private int fFixedLineNumber; private char[] fFixedInput; + private ScannerContext fReportMacros; + private boolean fReportUndefined; public MacroExpander(ILexerLog log, CharArrayMap<PreprocessorMacro> macroDictionary, LocationMap locationMap, LexerOptions lexOptions) { fDictionary= macroDictionary; @@ -147,8 +149,19 @@ 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 int ppOptions, + PreprocessorMacro macro, Token identifier, boolean completionMode, + ScannerContext scannerContext) throws OffsetLimitReachedException { + final boolean protectDefined= (ppOptions & CPreprocessor.PROTECT_DEFINED) != 0; + if ((ppOptions & CPreprocessor.REPORT_SIGNIFICANT_MACROS) != 0) { + fReportMacros= scannerContext; + fReportUndefined= (ppOptions & CPreprocessor.IGNORE_UNDEFINED_SIGNIFICANT_MACROS) == 0; + } else { + fReportMacros= null; + } + fImplicitMacroExpansions.clear(); fImageLocationInfos.clear(); @@ -170,7 +183,7 @@ public class MacroExpander { input.prepend(firstExpansion); - result= expandAll(input, forbidden, isPPCondition, null); + result= expandAll(input, forbidden, protectDefined, null); } catch (CompletionInMacroExpansionException e) { // for content assist in macro expansions, we return the list of tokens of the // parameter at the current cursor position and hope that they make sense if @@ -180,6 +193,7 @@ public class MacroExpander { result= e.getParameterTokens().cloneTokens(); } postProcessTokens(result); + fReportMacros= null; return result; } @@ -193,6 +207,7 @@ public class MacroExpander { fFixedInput= beforeExpansion.toCharArray(); fFixedCurrentFilename= filePath; fFixedLineNumber= lineNumber; + fReportMacros= null; Lexer lexer= new Lexer(fFixedInput, fLexOptions, fLog, this); try { @@ -240,6 +255,9 @@ public class MacroExpander { IdentityHashMap<PreprocessorMacro, PreprocessorMacro> 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 +369,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.significantMacro(macro); + } else if (fReportUndefined){ + fReportMacros.significantMacroUndefined(image); + } + } 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 getStartingLineNumber() {return 0;} - public int getEndingLineNumber() {return 0;} - public IASTFileLocation asFileLocation() {return this;} + 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 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..256fb07825e 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,6 +56,11 @@ final class ScannerContext { private CodeState fCurrentState= CodeState.eActive; private IncludeSearchPathElement fFoundOnPath; private String fFoundViaDirective; + private CharArraySet fInternalModifications; + private CharArrayObjectMap<char[]> fSignificantMacros; + private boolean fPragmaOnce; + private int fLoadedVersionCount; + /** * @param ctx @@ -60,6 +70,7 @@ final class ScannerContext { fLocationCtx= ctx; fParent= parent; fLexer= lexer; + fDepth = parent == null ? 0 : parent.fDepth+1; } public ScannerContext(ILocationCtx ctx, ScannerContext parent, TokenList tokens) { @@ -88,6 +99,13 @@ final class ScannerContext { } /** + * 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. */ public final Lexer getLexer() { @@ -297,4 +315,123 @@ final class ScannerContext { fFoundOnPath= foundOnPath; fFoundViaDirective= viaDirective; } + + public void trackSignificantMacros() { + fInternalModifications= new CharArraySet(5); + fSignificantMacros= new CharArrayObjectMap<char[]>(5); + } + + public void setPragmaOnce(boolean val) { + fPragmaOnce= val; + } + + public boolean isPragmaOnce() { + return fPragmaOnce; + } + + public void internalModification(char[] macroName) { + if (fInternalModifications != null) + fInternalModifications.put(macroName); + } + + public void significantMacro(IMacroBinding macro) { + final char[] macroName= macro.getNameCharArray(); + if (fInternalModifications != null && !fInternalModifications.containsKey(macroName)) { + fSignificantMacros.put(macroName, macro.getExpansion()); + } + } + + public void significantMacroDefined(char[] macroName) { + 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 (fInternalModifications != null && !fInternalModifications.containsKey(macroName)) { + fSignificantMacros.put(macroName, SignificantMacros.UNDEFINED); + } + } + + public CharArrayObjectMap<char[]> getSignificantMacros() { + return fSignificantMacros; + } + + public void propagateSignificantMacros() { + if (fInternalModifications == null) + return; + + if (fParent != null) { + final CharArraySet local = fParent.fInternalModifications; + if (local != null) { + final CharArrayObjectMap<char[]> significant = fParent.fSignificantMacros; + for (int i=0; i<fSignificantMacros.size(); i++) { + final char[] name = fSignificantMacros.keyAt(i); + if (!local.containsKey(name)) { + final char[] value= fSignificantMacros.getAt(i); + if (value == SignificantMacros.DEFINED) { + if (!local.containsKey(name)) { + fParent.addSignificantMacroDefined(name); + } + } else { + significant.put(name, value); + } + } + } + local.addAll(fInternalModifications); + } + } + fInternalModifications= null; + fSignificantMacros= null; + } + + public void addSignificantMacros(ISignificantMacros sm) { + if (fInternalModifications == null) + return; + + sm.accept(new ISignificantMacros.IVisitor() { + public boolean visitValue(char[] macro, char[] value) { + if (!fInternalModifications.containsKey(macro)) { + fSignificantMacros.put(macro, value); + } + return true; + } + public boolean visitUndefined(char[] macro) { + if (!fInternalModifications.containsKey(macro)) { + fSignificantMacros.put(macro, SignificantMacros.UNDEFINED); + } + return true; + } + public boolean visitDefined(char[] macro) { + if (!fInternalModifications.containsKey(macro)) { + fSignificantMacros.put(macro, SignificantMacros.DEFINED); + } + return true; + } + }); + } + + public int getLoadedVersionCount() { + return fLoadedVersionCount; + } + + public void setLoadedVersionCount(int count) { + fLoadedVersionCount= count; + } + + @Override + public String toString() { + if (fParent == null) + return fLocationCtx.toString(); + + return fParent.toString() + "\n" + fLocationCtx.toString(); //$NON-NLS-1$ + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/SignificantMacros.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/SignificantMacros.java new file mode 100644 index 00000000000..a997540fd5b --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/SignificantMacros.java @@ -0,0 +1,169 @@ +/******************************************************************************* + * 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.parser.scanner; + +import java.util.Arrays; +import java.util.Comparator; + +import org.eclipse.cdt.core.parser.ISignificantMacros; +import org.eclipse.cdt.core.parser.util.CharArrayObjectMap; +import org.eclipse.cdt.core.parser.util.CharArrayUtils; + +/** + * A set of static methods to encode Map<String, String> as an array of characters and to decode + * it back. + * + * The map is encoded as: + * <code><number_of_entries>,<key1><value1>...<keyN><valueN></code>. + * <p> + * Each string is encoded as: <code><number_of_characters>,<characters></code>. + * A <code>null</code> string is encoded as a single comma. + */ +public class SignificantMacros implements ISignificantMacros { + public static final char[] UNDEFINED = {}; + public static final char[] DEFINED = {}; + private static final int ENCODED_UNDEFINED = Character.MAX_VALUE; + private static final int ENCODED_DEFINED = Character.MAX_VALUE-1; + private static final Comparator<Object> SORTER = new Comparator<Object>() { + 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<char[]> sigMacros) { + fEncoded= encode(sigMacros); + } + + private char[] encode(CharArrayObjectMap<char[]> 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 { + 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; + 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 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..6f69f48146a 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,19 +15,18 @@ 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.BitSet; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashSet; 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 +41,20 @@ 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 +72,161 @@ 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<IIndexFileLocation, LocationTask> fLocationTasks; - public FileKey(int linkageID, URI uri) { - fUri= uri; + LinkageTask(int linkageID) { fLinkageID= linkageID; + fLocationTasks= new HashMap<IIndexFileLocation, LocationTask>(); + } + + 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); + private static class LocationTask { + private boolean fCountedUnknownVersion; + private boolean fStoredAVersion; + Object fTu; + UpdateKind fKind= UpdateKind.OTHER_HEADER; + private List<FileVersionTask> fVersionTasks= 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 fVersionTasks.isEmpty(); + final boolean countRequest= !fCountedUnknownVersion; + fCountedUnknownVersion= true; + return countRequest; + } + + return addVersionTask(ifile); + } + + /** + * Return whether the task needs to be counted. + */ + private boolean addVersionTask(IIndexFragmentFile ifile) { + FileVersionTask fc= findVersion(ifile); + if (fc != null) + return false; + + fc= new FileVersionTask(ifile); + boolean countRequest= true; + if (fCountedUnknownVersion) { + fCountedUnknownVersion= false; + countRequest= false; + } + + switch (fVersionTasks.size()) { + case 0: + fVersionTasks= Collections.singletonList(fc); + break; + case 1: + List<FileVersionTask> newList= new ArrayList<FileVersionTask>(2); + newList.add(fVersionTasks.get(0)); + newList.add(fc); + fVersionTasks= newList; + break; + default: + fVersionTasks.add(fc); + break; + } + return countRequest; + } + + void removeVersionTask(Iterator<FileVersionTask> it) { + if (fVersionTasks.size() == 1) { + fVersionTasks= Collections.emptyList(); + } else { + it.remove(); + } + } + + private FileVersionTask findVersion(IIndexFile ifile) { + for (FileVersionTask fc : fVersionTasks) { + if (fc.fIndexFile.equals(ifile)) + return fc; + } + return null; + } + + FileVersionTask findVersion(ISignificantMacros sigMacros) throws CoreException { + for (FileVersionTask fc : fVersionTasks) { + if (sigMacros.equals(fc.fIndexFile.getSignificantMacros())) + return fc; + } + return null; + } + + boolean isCompleted() { + for (FileVersionTask fc : fVersionTasks) { + if (fc.fOutdated) + return false; + } + if (fKind == UpdateKind.OTHER_HEADER) + return true; + + return fStoredAVersion; + } + + public boolean needsVersion() { + if (fKind == UpdateKind.OTHER_HEADER) + return false; + + return !fStoredAVersion; } } + public static class FileVersionTask { + private final IIndexFragmentFile fIndexFile; + private boolean fOutdated; + + FileVersionTask(IIndexFragmentFile file) { + fIndexFile= file; + fOutdated= true; + } + + void setUpdated() { + fOutdated= 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 +238,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 +276,12 @@ public abstract class AbstractIndexerTask extends PDOMWriter { private int fUpdateFlags= IIndexManager.UPDATE_ALL; private UnusedHeaderStrategy fIndexHeadersWithoutContext= UnusedHeaderStrategy.useDefaultLanguage; private boolean fIndexFilesWithoutConfiguration= true; - private HashMap<FileKey, IndexFileContent> fFileInfos= new HashMap<FileKey, IndexFileContent>(); - + private List<LinkageTask> fRequestsPerLinkage= new ArrayList<LinkageTask>(); + private Map<IIndexFile, IndexFileContent> fIndexContentCache= new HashMap<IIndexFile, IndexFileContent>(); + private Map<IIndexFileLocation, IIndexFile[]> fIndexFilesCache= new HashMap<IIndexFileLocation, IIndexFile[]>(); + private Object[] fFilesToUpdate; private List<Object> fFilesToRemove = new ArrayList<Object>(); - private List<String> fFilesUpFront= new ArrayList<String>(); private int fASTOptions; private int fForceNumberFiles= 0; @@ -197,7 +297,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { */ private final LinkedList<AbstractIndexerTask> fUrgentTasks; boolean fTaskCompleted; - + private IndexerProgress fInfo= new IndexerProgress(); public AbstractIndexerTask(Object[] filesToUpdate, Object[] filesToRemove, IndexerInputAdapter resolver, boolean fastIndexer) { super(resolver); @@ -228,8 +328,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,94 +340,120 @@ 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; + } + + private synchronized boolean hasUrgentTasks() { + return !fUrgentTasks.isEmpty(); + } + + /** + * Retrieves the first urgent task from the queue of urgent tasks. + * @return An urgent task, or {@code null} if there are no urgent tasks. + */ + private synchronized AbstractIndexerTask getUrgentTask() { + return fUrgentTasks.poll(); + } + protected abstract IWritableIndex createIndex(); protected abstract IIncludeFileResolutionHeuristics createIncludeHeuristics(); protected abstract IncludeFileContentProvider createReaderFactory(); - protected abstract AbstractLanguage[] getLanguages(String fileName); - protected ITodoTaskUpdater createTodoTaskUpdater() { return null; } - - protected IScannerInfo createDefaultScannerConfig(int linkageID) { - return new ScannerInfo(); + + /** + * @return array of linkage IDs that shall be parsed + */ + protected int[] getLinkagesToParse() { + return PDOMManager.IDS_FOR_LINKAGES_TO_INDEX; } - - protected String getASTPathForParsingUpFront() { - return "______"; //$NON-NLS-1$ + + protected IParserLogService getLogService() { + return ParserUtil.getParserLogService(); + } + + protected void logError(IStatus s) { + CCorePlugin.log(s); + } + + protected void logException(Throwable e) { + CCorePlugin.log(e); } - 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); + protected String getMessage(MessageKind kind, Object... arguments) { + switch (kind) { + case parsingFileTask: + return NLS.bind(Messages.AbstractIndexerTask_parsingFileTask, arguments); + case errorWhileParsing: + return NLS.bind(Messages.AbstractIndexerTask_errorWhileParsing, arguments); + case tooManyIndexProblems: + return Messages.AbstractIndexerTask_tooManyIndexProblems; } return null; } - - private final IASTTranslationUnit createAST(Object tu, AbstractLanguage language, FileContent codeReader, - IScannerInfo scanInfo, int options, boolean inContext, IProgressMonitor pm) throws CoreException { - if (codeReader == null) { - return null; - } - if (fResolver.isSourceUnit(tu)) { - options |= ILanguage.OPTION_IS_SOURCE_UNIT; + /** + * Makes a copy of the current progress information and returns it. + * @since 4.0 + */ + public IndexerProgress getProgressInformation() { + synchronized (fInfo) { + return new IndexerProgress(fInfo); } - 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$ - } - return null; + /** + * 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; } - if (fCodeReaderFactory == null) { - InternalFileContentProvider fileContentProvider = createInternalFileContentProvider(); - if (fIsFastIndexer) { - IndexBasedFileContentProvider ibfcp = new IndexBasedFileContentProvider(fIndex, fResolver, - language.getLinkageID(), fileContentProvider, this); - ibfcp.setSupportFillGapFromContextToHeader(inContext); - ibfcp.setFileSizeLimit(fFileSizeLimit); - fCodeReaderFactory= ibfcp; + } + + private final void reportFile(boolean wasCounted, UpdateKind kind) { + if (wasCounted) { + if (kind == UpdateKind.REQUIRED_SOURCE) { + updateFileCount(1, 0, 0); } else { - fCodeReaderFactory= fileContentProvider; - } - } 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(); + updateFileCount(0, 1, 1); } + } else { + updateFileCount(0, 0, 1); } } - private InternalFileContentProvider createInternalFileContentProvider() { - final IncludeFileContentProvider fileContentProvider = createReaderFactory(); - if (fileContentProvider instanceof InternalFileContentProvider) - return (InternalFileContentProvider) fileContentProvider; - - throw new IllegalArgumentException("Invalid file content provider"); //$NON-NLS-1$ - } - - protected IParserLogService getLogService() { - return ParserUtil.getParserLogService(); + /** + * Updates current progress information with the provided delta. + */ + private final void incrementRequestedFilesCount(int delta) { + synchronized (fInfo) { + fInfo.fRequestedFilesCount += delta; + } } public final void runTask(IProgressMonitor monitor) throws InterruptedException { @@ -354,7 +480,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { try { try { // Split into sources and headers, remove excluded sources. - HashMap<Integer, List<Object>> files= new HashMap<Integer, List<Object>>(); + HashMap<Integer, List<IIndexFileLocation>> files= new HashMap<Integer, List<IIndexFileLocation>>(); final ArrayList<IIndexFragmentFile> indexFilesToRemove= new ArrayList<IIndexFragmentFile>(); extractFiles(files, indexFilesToRemove, monitor); @@ -362,13 +488,16 @@ public abstract class AbstractIndexerTask extends PDOMWriter { // Remove files from index removeFilesInIndex(fFilesToRemove, indexFilesToRemove, monitor); - - parseFilesUpFront(monitor); - HashMap<Integer, List<Object>> moreFiles= null; + HashMap<Integer, List<IIndexFileLocation>> moreFiles= null; while (true) { for (int linkageID : getLinkagesToParse()) { - parseLinkage(linkageID, files, monitor); + final List<IIndexFileLocation> filesForLinkage = files.get(linkageID); + if (filesForLinkage != null) { + parseLinkage(linkageID, filesForLinkage, monitor); + fIndexContentCache.clear(); + fIndexFilesCache.clear(); + } if (hasUrgentTasks()) break; } @@ -390,8 +519,8 @@ public abstract class AbstractIndexerTask extends PDOMWriter { if (moreFiles == null) { moreFiles = files; } else { - for (Map.Entry<Integer, List<Object>> entry : files.entrySet()) { - List<Object> list= moreFiles.get(entry.getKey()); + for (Map.Entry<Integer, List<IIndexFileLocation>> entry : files.entrySet()) { + List<IIndexFileLocation> list= moreFiles.get(entry.getKey()); if (list == null) { moreFiles.put(entry.getKey(), entry.getValue()); } else { @@ -400,7 +529,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { } } // Extract files from the urgent task. - files = new HashMap<Integer, List<Object>>(); + files = new HashMap<Integer, List<IIndexFileLocation>>(); fFilesToUpdate = urgentTask.fFilesToUpdate; fForceNumberFiles = urgentTask.fForceNumberFiles; fFilesToRemove = urgentTask.fFilesToRemove; @@ -427,49 +556,24 @@ 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); + fIndex.acquireWriteLock(); try { fIndex.getWritableFragment().setProperty(IIndexFragment.PROPERTY_RESUME_INDEXER, String.valueOf(value)); } finally { - fIndex.releaseWriteLock(1); + fIndex.releaseWriteLock(); } } - private void extractFiles(HashMap<Integer, List<Object>> files, List<IIndexFragmentFile> iFilesToRemove, + private void extractFiles(HashMap<Integer, List<IIndexFileLocation>> files, List<IIndexFragmentFile> 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; + BitSet linkages= new BitSet(); for (final Object tu : fFilesToUpdate) { if (monitor.isCanceled()) return; @@ -480,39 +584,35 @@ 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); + linkages.clear(); + 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++; + linkages.set(linkageID); } } } + if (!foundInLinkage && requestUpdate(linkageID, ifl, null, tu, updateKind)) { + linkages.set(linkageID); + count++; + } } } - // handle other files present in index + // Handle other files present in index. for (IIndexFragmentFile ifile : indexFiles) { if (ifile != null) { IIndexInclude ctx= ifile.getParsedInContext(); @@ -520,20 +620,18 @@ 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); + final int linkageID = ifile.getLinkageID(); + if (update && requestUpdate(linkageID, ifl, ifile, tu, UpdateKind.OTHER_HEADER)) { count++; + linkages.set(linkageID); } } } } + for (int lid = linkages.nextSetBit(0); lid >= 0; lid= linkages.nextSetBit(lid+1)) { + addPerLinkage(lid, ifl, files); + } } synchronized (this) { incrementRequestedFilesCount(count - fFilesToUpdate.length); @@ -541,6 +639,36 @@ public abstract class AbstractIndexerTask extends PDOMWriter { } } + private void addPerLinkage(int linkageID, IIndexFileLocation ifl, HashMap<Integer, List<IIndexFileLocation>> files) { + List<IIndexFileLocation> list= files.get(linkageID); + if (list == null) { + list= new LinkedList<IIndexFileLocation>(); + files.put(linkageID, list); + } + list.add(ifl); + } + + 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,84 +683,64 @@ 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 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); - } - info.fIsUpdated= true; - info.clearCaches(); - } - - 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 long computeFileContentsHash(Object tu) { + FileContent codeReader= fResolver.getCodeReader(tu); + return codeReader != null ? codeReader.getContentsHash() : 0; } - private boolean isHeaderConfigChange(Object tu, IIndexFragmentFile ifile) { - return 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 IIndexFragmentFile getFile(int linkageID, IIndexFragmentFile[] indexFiles) throws CoreException { - for (IIndexFragmentFile ifile : indexFiles) { - if (ifile != null && ifile.getLinkageID() == linkageID) { - return ifile; - } + private LinkageTask createRequestMap(int linkageID) { + LinkageTask map= findRequestMap(linkageID); + if (map == null) { + map= new LinkageTask(linkageID); + fRequestsPerLinkage.add(map); } - return null; + return map; } - private void takeFile(IIndexFragmentFile ifile, IIndexFragmentFile[] indexFiles) { - for (int i = 0; i < indexFiles.length; i++) { - if (indexFiles[i] == ifile) { - indexFiles[i]= null; - return; - } + private LinkageTask findRequestMap(int linkageID) { + for (LinkageTask map : fRequestsPerLinkage) { + if (map.fLinkageID == linkageID) + return map; } + return null; } - - private void store(Object tu, int linkageID, boolean isSourceUnit, HashMap<Integer, List<Object>> files) { - Integer key = getFileListKey(linkageID, isSourceUnit); - List<Object> list= files.get(key); - if (list == null) { - list= new LinkedList<Object>(); - files.put(key, list); + + @Override + protected void reportFileWrittenToIndex(FileInAST file, IIndexFragmentFile ifile) throws CoreException { + final FileContentKey fck = file.fFileContentKey; + boolean wasCounted= 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.findVersion(ifile); + if (v != null) { + wasCounted= v.fOutdated; + v.setUpdated(); + } else { + // We have added a version, the request is fulfilled. + wasCounted= locTask.fCountedUnknownVersion; + locTask.fCountedUnknownVersion= false; + } + locTask.fStoredAVersion= true; + } } - list.add(tu); - } - - private Integer getFileListKey(int linkageID, boolean isSourceUnit) { - Integer key= new Integer(linkageID * 2 + (isSourceUnit ? 0 : 1)); - return key; + fIndexContentCache.remove(ifile); + fIndexFilesCache.remove(file.fFileContentKey.getLocation()); + reportFile(wasCounted, kind); } private void removeFilesInIndex(List<Object> filesToRemove, List<IIndexFragmentFile> indexFilesToRemove, IProgressMonitor monitor) throws InterruptedException, CoreException { if (!filesToRemove.isEmpty() || !indexFilesToRemove.isEmpty()) { - fIndex.acquireWriteLock(1); + fIndex.acquireWriteLock(); try { for (Object tu : filesToRemove) { if (monitor.isCanceled()) { @@ -643,7 +751,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { continue; IIndexFragmentFile[] ifiles= fIndex.getWritableFiles(ifl); for (IIndexFragmentFile ifile : ifiles) { - fIndex.clearFile(ifile, null); + fIndex.clearFile(ifile); } incrementRequestedFilesCount(-1); } @@ -651,205 +759,182 @@ public abstract class AbstractIndexerTask extends PDOMWriter { if (monitor.isCanceled()) { return; } - fIndex.clearFile(ifile, null); + fIndex.clearFile(ifile); incrementRequestedFilesCount(-1); } } finally { - fIndex.releaseWriteLock(1); + fIndex.releaseWriteLock(); } } 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<Integer, List<Object>> fileListMap, IProgressMonitor monitor) + private void parseLinkage(int linkageID, List<IIndexFileLocation> files, IProgressMonitor monitor) throws CoreException, InterruptedException { - // Sources - List<Object> files= fileListMap.get(getFileListKey(linkageID, true)); - if (files != null) { - for (Iterator<Object> iter = files.iterator(); iter.hasNext();) { - Object tu = iter.next(); + LinkageTask map = findRequestMap(linkageID); + if (map == null || files == null || files.isEmpty()) + return; + + // First parse the required sources + for (Iterator<IIndexFileLocation> it= files.iterator(); it.hasNext();) { + IIndexFileLocation ifl= it.next(); + LocationTask locTask = map.find(ifl); + if (locTask == null || locTask.isCompleted()) { + it.remove(); + } else if (locTask.fKind == UpdateKind.REQUIRED_SOURCE) { 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 - } + final Object tu = locTask.fTu; + final IScannerInfo scannerInfo= fResolver.getBuildConfiguration(linkageID, tu); + parseFile(tu, linkageID, ifl, scannerInfo, null, monitor); + } + } + + // Files with context + for (Iterator<IIndexFileLocation> it= files.iterator(); it.hasNext();) { + IIndexFileLocation ifl= it.next(); + LocationTask locTask = map.find(ifl); + if (locTask == null || locTask.isCompleted()) { + it.remove(); + } else { + for (FileVersionTask versionTask : locTask.fVersionTasks) { + if (versionTask.fOutdated) { + if (monitor.isCanceled() || hasUrgentTasks()) + return; + parseVersionInContext(linkageID, map, ifl, versionTask, locTask.fTu, + new LinkedHashSet<IIndexFile>(), monitor); } } - iter.remove(); } } - // Headers with context - HashMap<IIndexFragmentFile, Object> contextMap= new HashMap<IIndexFragmentFile, Object>(); - files= fileListMap.get(getFileListKey(linkageID, false)); - if (files != null) { - for (Iterator<Object> 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(); + // Files without context + for (Iterator<IIndexFileLocation> it= files.iterator(); it.hasNext();) { + IIndexFileLocation ifl= it.next(); + LocationTask locTask = map.find(ifl); + if (locTask == null || locTask.isCompleted()) { + it.remove(); + } else { + if (locTask.needsVersion()) { + if (monitor.isCanceled() || hasUrgentTasks()) + return; + final Object tu = locTask.fTu; + final IScannerInfo scannerInfo= fResolver.getBuildConfiguration(linkageID, tu); + parseFile(tu, linkageID, ifl, scannerInfo, null, monitor); + if (locTask.isCompleted()) + it.remove(); + } } + } - // Headers without context - contextMap= null; - for (Iterator<Object> 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 + // Delete remaining files. + fIndex.acquireWriteLock(); + try { + for (IIndexFileLocation ifl : files) { + LocationTask locTask = map.find(ifl); + if (locTask != null && !locTask.isCompleted()) { + if (!locTask.needsVersion()) { + if (monitor.isCanceled() || hasUrgentTasks()) + return; + Iterator<FileVersionTask> it= locTask.fVersionTasks.iterator(); + while (it.hasNext()) { + FileVersionTask v = it.next(); + if (v.fOutdated) { + fIndex.clearFile(v.fIndexFile); + reportFile(true, locTask.fKind); + locTask.removeVersionTask(it); + fIndexContentCache.remove(v.fIndexFile); + fIndexFilesCache.remove(ifl); + } + } } } - iter.remove(); } + } finally { + fIndex.releaseWriteLock(); } } - private synchronized boolean hasUrgentTasks() { - return !fUrgentTasks.isEmpty(); - } + private void parseVersionInContext(int linkageID, LinkageTask map, IIndexFileLocation ifl, + final FileVersionTask versionTask, Object tu, LinkedHashSet<IIndexFile> safeGuard, + IProgressMonitor monitor) throws CoreException, InterruptedException { + final IIndexFragmentFile headerFile = versionTask.fIndexFile; + + final int safeguardSize= safeGuard.size(); + for(;;) { + // Look for a context and parse the file + IIndexFragmentFile ctxFile = findContextFile(linkageID, map, versionTask, safeGuard, monitor); + if (ctxFile == null || ctxFile == headerFile) + return; + + Object contextTu= fResolver.getInputFile(ctxFile.getLocation()); + if (contextTu == null) + return; + + final IScannerInfo scannerInfo= fResolver.getBuildConfiguration(linkageID, contextTu); + FileContext ctx= new FileContext(ctxFile, headerFile); + parseFile(tu, linkageID, ifl, scannerInfo, ctx, monitor); + if (!ctx.fLostPragmaOnceSemantics) + return; - /** - * Retrieves the first urgent task from the queue of urgent tasks. - * @return An urgent task, or {@code null} if there are no urgent tasks. - */ - private synchronized AbstractIndexerTask getUrgentTask() { - return fUrgentTasks.poll(); + // Try the next context + restoreSet(safeGuard, safeguardSize); + } } - private static final Object NO_CONTEXT= new Object(); - - private Object findContext(int linkageID, IIndexFragmentFile ifile, HashMap<IIndexFragmentFile, Object> contextMap) { - Object cachedContext= contextMap.get(ifile); - if (cachedContext != null) { - return cachedContext == NO_CONTEXT ? null : cachedContext; + private void restoreSet(LinkedHashSet<?> set, int restoreSize) { + for (Iterator<?> it = set.iterator(); it.hasNext();) { + it.next(); + if (restoreSize == 0) { + it.remove(); + } else { + restoreSize--; + } } - 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; + private IIndexFragmentFile findContextFile(int linkageID, LinkageTask map, + final FileVersionTask versionTask, LinkedHashSet<IIndexFile> safeGuard, IProgressMonitor monitor) + throws CoreException, InterruptedException { + IIndexFragmentFile ctxFile= versionTask.fIndexFile; + for(;;) { + IIndexInclude ctxInclude= ctxFile.getParsedInContext(); + if (ctxInclude == null) + return ctxFile; + + IIndexFragmentFile nextCtx= (IIndexFragmentFile) ctxInclude.getIncludedBy(); + if (!fIndex.isWritableFile(nextCtx)) + return ctxFile; + + // Found a recursion + if (!safeGuard.add(nextCtx)) + return null; + + final IIndexFileLocation ctxIfl = nextCtx.getLocation(); + LocationTask ctxTask= map.find(ctxIfl); + if (ctxTask != null) { + FileVersionTask ctxVersionTask = ctxTask.findVersion(nextCtx); + if (ctxVersionTask != null && ctxVersionTask.fOutdated) { + // Handle the context first. + parseVersionInContext(linkageID, map, ctxIfl, ctxVersionTask, ctxTask.fTu, + safeGuard, monitor); + if (ctxVersionTask.fOutdated // This is unexpected. + || !versionTask.fOutdated) // Our file was parsed. + return null; + + // The file is no longer a context, look for a different one. + nextCtx= ctxFile; } } - } catch (CoreException e) { - CCorePlugin.log(e); + ctxFile= nextCtx; } - return null; } + private void parseFile(Object tu, int linkageID, IIndexFileLocation ifl, IScannerInfo scanInfo, - boolean inContext, IProgressMonitor pm) throws CoreException, InterruptedException { - IPath path= getPathForLabel(ifl); + FileContext ctx, IProgressMonitor pm) throws CoreException, InterruptedException { + IPath path= getLabel(ifl); AbstractLanguage[] langs= fResolver.getLanguages(tu, true); AbstractLanguage lang= null; for (AbstractLanguage lang2 : langs) { @@ -871,10 +956,12 @@ public abstract class AbstractIndexerTask extends PDOMWriter { path.lastSegment(), path.removeLastSegments(1).toString())); long start= System.currentTimeMillis(); FileContent codeReader= fResolver.getCodeReader(tu); - IASTTranslationUnit ast= createAST(tu, lang, codeReader, scanInfo, fASTOptions, inContext, pm); + IIndexFile[] ctxFiles = ctx == null ? null : new IIndexFile[] {ctx.fContext, ctx.fOldFile}; + + IASTTranslationUnit ast= createAST(tu, lang, codeReader, scanInfo, fASTOptions, ctxFiles, pm); fStatistics.fParsingTime += System.currentTimeMillis() - start; if (ast != null) { - writeToIndex(linkageID, ast, codeReader.getContentsHash(), computeHashCode(scanInfo), pm); + writeToIndex(linkageID, ast, codeReader.getContentsHash(), ctx, pm); } } catch (CoreException e) { th= e; @@ -894,80 +981,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { } } - private void writeToIndex(final int linkageID, IASTTranslationUnit ast, long fileContentsHash, - int configHash, IProgressMonitor pm) throws CoreException, InterruptedException { - HashSet<IIndexFileLocation> enteredFiles= new HashSet<IIndexFileLocation>(); - ArrayList<IIndexFileLocation> orderedIFLs= new ArrayList<IIndexFileLocation>(); - - final IIndexFileLocation topIfl = fResolver.resolveASTPath(ast.getFilePath()); - enteredFiles.add(topIfl); - IDependencyTree tree= ast.getDependencyTree(); - IASTInclusionNode[] inclusions= tree.getInclusions(); - for (IASTInclusionNode inclusion : inclusions) { - collectOrderedIFLs(linkageID, inclusion, enteredFiles, orderedIFLs); - } - - IndexFileContent info= getFileInfo(linkageID, topIfl); - if (info != null && info.fRequestUpdate && !info.fIsUpdated) { - orderedIFLs.add(topIfl); - } - - IIndexFileLocation[] ifls= orderedIFLs.toArray(new IIndexFileLocation[orderedIFLs.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; - } - } - } - - private void collectOrderedIFLs(final int linkageID, IASTInclusionNode inclusion, - HashSet<IIndexFileLocation> enteredFiles, ArrayList<IIndexFileLocation> 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; - } - } - info= createFileInfo(new FileKey(linkageID, ifl.getURI()), ifile); - if (ifile == null) { - info.fRequestIsCounted= false; - info.fRequestUpdate= true; - } - } - 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) { + private IPath getLabel(IIndexFileLocation ifl) { String fullPath= ifl.getFullPath(); if (fullPath != null) { return new Path(fullPath); @@ -992,7 +1006,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { if (CCorePlugin.PLUGIN_ID.equals(s.getPlugin())) throw (CoreException) e; } - + // mask errors in order to avoid dialog from platform Throwable exception = s.getException(); if (exception != null) { @@ -1021,100 +1035,226 @@ public abstract class AbstractIndexerTask extends PDOMWriter { } return e; } - - protected void logError(IStatus s) { - CCorePlugin.log(s); - } - - protected void logException(Throwable e) { - CCorePlugin.log(e); - } - private static int computeHashCode(IScannerInfo scannerInfo) { - int result= 0; - Map<String, String> macros= scannerInfo.getDefinedSymbols(); - if (macros != null) { - for (Entry<String, String> 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); - } + private final IASTTranslationUnit createAST(Object tu, AbstractLanguage language, + FileContent codeReader, IScannerInfo scanInfo, int options, + IIndexFile[] ctx2header, IProgressMonitor pm) throws CoreException { + if (codeReader == null) { + return null; + } + if (fResolver.isSourceUnit(tu)) { + options |= ILanguage.OPTION_IS_SOURCE_UNIT; + } + if (fFileSizeLimit > 0 && fResolver.getFileSize(codeReader.getFileLocation()) > fFileSizeLimit) { + if (fShowActivity) { + trace("Indexer: Skipping large file " + codeReader.getFileLocation()); //$NON-NLS-1$ } + return null; } - String[] a= scannerInfo.getIncludePaths(); - if (a != null) { - for (String element : a) { - result= addToHashcode(result, element); - + if (fCodeReaderFactory == null) { + InternalFileContentProvider fileContentProvider = createInternalFileContentProvider(); + if (fIsFastIndexer) { + IndexBasedFileContentProvider ibfcp = new IndexBasedFileContentProvider(fIndex, fResolver, + language.getLinkageID(), fileContentProvider, this); + ibfcp.setContextToHeaderGap(ctx2header); + ibfcp.setFileSizeLimit(fFileSizeLimit); + fCodeReaderFactory= ibfcp; + } else { + fCodeReaderFactory= fileContentProvider; } + fCodeReaderFactory.setIncludeResolutionHeuristics(createIncludeHeuristics()); + } else if (fIsFastIndexer) { + final IndexBasedFileContentProvider ibfcp = (IndexBasedFileContentProvider) fCodeReaderFactory; + ibfcp.setContextToHeaderGap(ctx2header); + ibfcp.setLinkage(language.getLinkageID()); + } + + IASTTranslationUnit ast= language.getASTTranslationUnit(codeReader, scanInfo, fCodeReaderFactory, + fIndex, options, getLogService()); + if (pm.isCanceled()) { + return null; } - if (scannerInfo instanceof IExtendedScannerInfo) { - IExtendedScannerInfo esi= (IExtendedScannerInfo) scannerInfo; - a= esi.getIncludeFiles(); - if (a != null) { - for (String element : a) { - result= addToHashcode(result, element); + return ast; + } - } - } - 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); - } - } + private InternalFileContentProvider createInternalFileContentProvider() { + final IncludeFileContentProvider fileContentProvider = createReaderFactory(); + if (fileContentProvider instanceof InternalFileContentProvider) + return (InternalFileContentProvider) fileContentProvider; + + throw new IllegalArgumentException("Invalid file content provider"); //$NON-NLS-1$ + } + + private void writeToIndex(final int linkageID, IASTTranslationUnit ast, long fileContentsHash, + FileContext ctx, IProgressMonitor pm) throws CoreException, InterruptedException { + HashSet<FileContentKey> enteredFiles= new HashSet<FileContentKey>(); + ArrayList<FileInAST> orderedFileKeys= new ArrayList<FileInAST>(); + + final IIndexFileLocation topIfl = fResolver.resolveASTPath(ast.getFilePath()); + FileContentKey topKey = new FileContentKey(linkageID, topIfl, ast.getSignificantMacros()); + enteredFiles.add(topKey); + IDependencyTree tree= ast.getDependencyTree(); + IASTInclusionNode[] inclusions= tree.getInclusions(); + for (IASTInclusionNode inclusion : inclusions) { + collectOrderedFileKeys(linkageID, inclusion, enteredFiles, orderedFileKeys); + } + + IIndexFile newFile= selectIndexFile(linkageID, topIfl, ast.getSignificantMacros()); + if (ctx != null) { + orderedFileKeys.add(new FileInAST(null, topKey, fileContentsHash)); + if (newFile != null && fIndex.isWritableFile(newFile)) { + // File can be reused + ctx.fNewFile= (IIndexFragmentFile) newFile; + } + } else if (newFile == null) { + orderedFileKeys.add(new FileInAST(null, topKey, fileContentsHash)); + } + + FileInAST[] fileKeys= orderedFileKeys.toArray(new FileInAST[orderedFileKeys.size()]); + try { + addSymbols(ast, fileKeys, fIndex, false, ctx, 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; } - return result; } - private static int addToHashcode(int result, String key) { - return result * 31 + key.hashCode(); + private void collectOrderedFileKeys(final int linkageID, IASTInclusionNode inclusion, + HashSet<FileContentKey> enteredFiles, ArrayList<FileInAST> orderedFileKeys) throws CoreException { + final IASTPreprocessorIncludeStatement include= inclusion.getIncludeDirective(); + if (include.createsAST()) { + 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 && selectIndexFile(linkageID, ifl, include.getSignificantMacros()) == null) { + orderedFileKeys.add(new FileInAST(include, fileKey, include.getContentsHash())); + } + } } - private long computeFileContentsHash(Object tu) { - FileContent codeReader= fResolver.getCodeReader(tu); - return codeReader != null ? codeReader.getContentsHash() : 0; + private 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.fCountedUnknownVersion) { + locTask.fCountedUnknownVersion= false; + reportFile(true, locTask.fKind); + } else { + for (FileVersionTask fc : locTask.fVersionTasks) { + if (fc.fOutdated) { + reportFile(true, locTask.fKind); + fc.setUpdated(); + } + } + } + } + } + } } - 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.fOutdated) return null; + } + } + IndexFileContent fc= fIndexContentCache.get(file); + if (fc == null) { + fc= new IndexFileContent(file); + fIndexContentCache.put(file, fc); + } + return fc; + } + + IIndexFile selectIndexFile(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.fOutdated ? null : task.fIndexFile; } } - return info; + } + + IIndexFile[] files = getAvailableIndexFiles(linkageID, ifl); + for (IIndexFile file : files) { + if (sigMacros.equals(file.getSignificantMacros())) + return file; } return null; } - - protected String getMessage(MessageKind kind, Object... arguments) { - switch (kind) { - case parsingFileTask: - return NLS.bind(Messages.AbstractIndexerTask_parsingFileTask, arguments); - case errorWhileParsing: - return NLS.bind(Messages.AbstractIndexerTask_errorWhileParsing, arguments); - case tooManyIndexProblems: - return Messages.AbstractIndexerTask_tooManyIndexProblems; + + 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) { + for (FileVersionTask fileVersion : request.fVersionTasks) { + final IIndexFile indexFile = fileVersion.fIndexFile; + if (md.satisfies(indexFile.getSignificantMacros())) { + if (fileVersion.fOutdated) + return null; + return indexFile; + } + } + } + } + + IIndexFile[] files = getAvailableIndexFiles(linkageID, ifl); + for (IIndexFile indexFile : files) { + if (md.satisfies(indexFile.getSignificantMacros())) { + return indexFile; + } } return null; } - /** - * @return array of linkage IDs that should be parsed - */ - protected int[] getLinkagesToParse() { - return PDOMManager.IDS_FOR_LINKAGES_TO_INDEX; + public IIndexFile[] getAvailableIndexFiles(int linkageID, IIndexFileLocation ifl) + throws CoreException { + IIndexFile[] files= fIndexFilesCache.get(ifl); + if (files == null) { + if (fResolver.canBePartOfSDK(ifl)) { + // Check for a version in potentially another pdom. + files= fIndex.getFiles(linkageID, ifl); + } else { + IIndexFragmentFile[] fragFiles = fIndex.getWritableFiles(linkageID, ifl); + int j= 0; + for (int i = 0; i < fragFiles.length; i++) { + if (fragFiles[i].hasContent()) { + if (j != i) + fragFiles[j]= fragFiles[i]; + j++; + } + } + if (j == fragFiles.length) { + files= fragFiles; + } else { + files= new IIndexFile[j]; + System.arraycopy(fragFiles, 0, files, 0, j); + } + } + fIndexFilesCache.put(ifl, files); + } + return files; } -}
\ 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<PDOMFile> locations = new ArrayList<PDOMFile>(); - 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/PDOMManager.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMManager.java index e9d85a73bd2..16abe010082 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMManager.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMManager.java @@ -1091,12 +1091,14 @@ public class PDOMManager implements IWritableIndexManager, IListener { assert monitor != null; Thread th= null; if (waitMaxMillis != FOREVER) { + final Thread callingThread= Thread.currentThread(); th= new Thread() { @Override public void run() { try { Thread.sleep(waitMaxMillis); monitor.setCanceled(true); + callingThread.interrupt(); } catch (InterruptedException e) { } } 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<Thread, DebugLockInfo>(); } } + 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..7bf753147d3 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,8 +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; import java.util.Iterator; @@ -47,11 +45,14 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceAlias; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; +import org.eclipse.cdt.core.index.IIndexFile; 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,36 @@ import org.eclipse.osgi.util.NLS; * @since 4.0 */ abstract public class PDOMWriter { + public static class FileInAST { + final IASTPreprocessorIncludeStatement fIncludeStatement; + final FileContentKey fFileContentKey; + final long fContentsHash; + + public FileInAST(IASTPreprocessorIncludeStatement includeStmt, FileContentKey key, long contentsHash) { + fIncludeStatement= includeStmt; + fFileContentKey= key; + fContentsHash= contentsHash; + } + + @Override + public String toString() { + return fFileContentKey.toString(); + } + } + + public static class FileContext { + final IIndexFragmentFile fContext; + final IIndexFragmentFile fOldFile; + IIndexFragmentFile fNewFile; + public boolean fLostPragmaOnceSemantics; + + public FileContext(IIndexFragmentFile context, IIndexFragmentFile oldFile) { + fContext= context; + fOldFile= oldFile; + fNewFile= null; + } + } + public static int SKIP_ALL_REFERENCES= -1; public static int SKIP_TYPE_REFERENCES= 1; public static int SKIP_MACRO_REFERENCES= 2; @@ -77,9 +108,24 @@ abstract public class PDOMWriter { public static int SKIP_NO_REFERENCES= 0; private static class Symbols { - ArrayList<IASTName[]> fNames= new ArrayList<IASTName[]>(); - ArrayList<IASTPreprocessorStatement> fMacros= new ArrayList<IASTPreprocessorStatement>(); - ArrayList<IASTPreprocessorIncludeStatement> fIncludes= new ArrayList<IASTPreprocessorIncludeStatement>(); + final ArrayList<IASTName[]> fNames= new ArrayList<IASTName[]>(); + final ArrayList<IASTPreprocessorStatement> fMacros= new ArrayList<IASTPreprocessorStatement>(); + final ArrayList<IASTPreprocessorIncludeStatement> fIncludes= new ArrayList<IASTPreprocessorIncludeStatement>(); + } + + private static class Data { + final IASTTranslationUnit fAST; + final FileInAST[] fSelectedFiles; + final IWritableIndex fIndex; + final Map<IASTPreprocessorIncludeStatement, Symbols> fSymbolMap = new HashMap<IASTPreprocessorIncludeStatement, Symbols>(); + final Set<IASTPreprocessorIncludeStatement> fContextIncludes = new HashSet<IASTPreprocessorIncludeStatement>(); + final List<IStatus> fStati= new ArrayList<IStatus>(); + + public Data(IASTTranslationUnit ast, FileInAST[] selectedFiles, IWritableIndex index) { + fAST= ast; + fSelectedFiles= selectedFiles; + fIndex= index; + } } private boolean fShowProblems; @@ -90,7 +136,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 +185,45 @@ abstract public class PDOMWriter { * * When flushIndex is set to <code>false</code>, 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, - ITodoTaskUpdater taskUpdater, IProgressMonitor pm) throws InterruptedException, CoreException { + final protected void addSymbols(IASTTranslationUnit ast, FileInAST[] selectedFiles, + IWritableIndex index, boolean flushIndex, FileContext ctx, + ITodoTaskUpdater taskUpdater, IProgressMonitor pm) throws InterruptedException, + CoreException { if (fShowProblems) { fShowInclusionProblems= true; fShowScannerProblems= true; fShowSyntaxProblems= true; } - final Map<IIndexFileLocation, Symbols> symbolMap= new HashMap<IIndexFileLocation, Symbols>(); - for (IIndexFileLocation ifl : ifls) { - prepareInMap(symbolMap, ifl); + + Data data= new Data(ast, selectedFiles, index); + for (FileInAST file : selectedFiles) { + data.fSymbolMap.put(file.fIncludeStatement, new Symbols()); } - ArrayList<IStatus> stati= new ArrayList<IStatus>(); + - HashSet<IASTPreprocessorIncludeStatement> contextIncludes= new HashSet<IASTPreprocessorIncludeStatement>(); - extractSymbols(ast, symbolMap, contextIncludes); + // Extract symbols from AST + extractSymbols(data); - // name resolution - resolveNames(symbolMap, ifls, stati, pm); + // Name resolution + resolveNames(data, pm); - // index update - storeSymbolsInIndex(symbolMap, ifls, ast.getLinkage().getLinkageID(), fileContentsHash, - configHash, contextIncludes, index, readlockCount, flushIndex, stati, pm); + // Index update + storeSymbolsInIndex(data, ctx, flushIndex, pm); + // Tasks update if (taskUpdater != null) { - taskUpdater.updateTasks(ast.getComments(), ifls); + Set<IIndexFileLocation> locations= new HashSet<IIndexFileLocation>(); + for (FileInAST file : selectedFiles) { + locations.add(file.fFileContentKey.getLocation()); + } + taskUpdater.updateTasks(ast.getComments(), locations.toArray(new IIndexFileLocation[locations.size()])); } - if (!stati.isEmpty()) { + if (!data.fStati.isEmpty()) { + List<IStatus> stati = data.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,60 +241,73 @@ abstract public class PDOMWriter { } } - private void storeSymbolsInIndex(final Map<IIndexFileLocation, Symbols> symbolMap, IIndexFileLocation[] ifls, - int linkageID, long fileContentsHash, int configHash, - HashSet<IASTPreprocessorIncludeStatement> contextIncludes, IWritableIndex index, int readlockCount, - boolean flushIndex, ArrayList<IStatus> stati, IProgressMonitor pm) + private void storeSymbolsInIndex(final Data data, FileContext ctx, boolean flushIndex, IProgressMonitor pm) throws InterruptedException, CoreException { - for (int i= 0; i < ifls.length; i++) { + final IIndexFragmentFile newFile= ctx == null ? null : ctx.fNewFile; + 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 fileInAST= data.fSelectedFiles[i]; + if (fileInAST != null) { if (fShowActivity) { - trace("Indexer: adding " + ifl.getURI()); //$NON-NLS-1$ + trace("Indexer: adding " + fileInAST.fFileContentKey.getLocation().getURI()); //$NON-NLS-1$ } Throwable th= null; - YieldableIndexLock lock = new YieldableIndexLock(index, readlockCount, flushIndex); + YieldableIndexLock lock = new YieldableIndexLock(data.fIndex, flushIndex); lock.acquire(); try { - storeFileInIndex(index, ifl, symbolMap, linkageID, fileContentsHash, configHash, - contextIncludes, lock); - } catch (RuntimeException e) { + final boolean isReplacement= ctx != null && fileInAST.fIncludeStatement == null; + IIndexFragmentFile ifile= null; + if (!isReplacement || newFile == null) { + ifile= storeFileInIndex(data, fileInAST, linkageID, lock); + reportFileWrittenToIndex(fileInAST, ifile); + } + + if (isReplacement) { + if (ifile == null) + ifile= newFile; + if (ctx != null && !ctx.fOldFile.equals(ifile) && ifile != null) { + if (ctx.fOldFile.hasPragmaOnceSemantics() && + !ifile.hasPragmaOnceSemantics()) { + data.fIndex.transferContext(ctx.fOldFile, ifile); + ctx.fLostPragmaOnceSemantics= true; + } else { + data.fIndex.transferIncluders(ctx.fOldFile, ifile); + } + } + } + } catch (RuntimeException e) { th= e; } catch (StackOverflowError e) { th= e; } catch (AssertionError e) { th= e; } finally { - // When the caller holds a read-lock, the result cache of the index is never cleared. + // Because 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 (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, + fileInAST.fFileContentKey.getLocation().getURI().getPath()), th)); } fStatistics.fAddToIndexTime += lock.getCumulativeLockTime(); } } } - private void resolveNames(final Map<IIndexFileLocation, Symbols> symbolMap, IIndexFileLocation[] ifls, - ArrayList<IStatus> 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<IASTName[]> names= symbols.fNames; boolean reported= false; @@ -286,8 +350,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 +362,44 @@ abstract public class PDOMWriter { fStatistics.fResolutionTime += System.currentTimeMillis()-start; } - private void extractSymbols(IASTTranslationUnit ast, final Map<IIndexFileLocation, Symbols> symbolMap, - Collection<IASTPreprocessorIncludeStatement> contextIncludes) throws CoreException { - final HashSet<IIndexFileLocation> contextIFLs= new HashSet<IIndexFileLocation>(); - final IIndexFileLocation astIFL = fResolver.resolveASTPath(ast.getFilePath()); - + private void extractSymbols(Data data) throws CoreException { int unresolvedIncludes= 0; + final IASTTranslationUnit ast = data.fAST; + final Map<IASTPreprocessorIncludeStatement, Symbols> 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 +411,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 +431,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,57 +489,45 @@ abstract public class PDOMWriter { return false; } - private void addToMap(Map<IIndexFileLocation, Symbols> map, IIndexFileLocation location, IASTName[] thing) { - Symbols lists= map.get(location); + private void addToMap(Map<IASTPreprocessorIncludeStatement, Symbols> symbolMap, IASTPreprocessorIncludeStatement owner, IASTName[] thing) { + Symbols lists= symbolMap.get(owner); if (lists != null) lists.fNames.add(thing); } - private void addToMap(Map<IIndexFileLocation, Symbols> map, IIndexFileLocation location, - IASTPreprocessorIncludeStatement thing) { - Symbols lists= map.get(location); + private void addToMap(Map<IASTPreprocessorIncludeStatement, Symbols> symbolMap, IASTPreprocessorIncludeStatement owner, IASTPreprocessorIncludeStatement thing) { + Symbols lists= symbolMap.get(owner); if (lists != null) lists.fIncludes.add(thing); } - private void addToMap(Map<IIndexFileLocation, Symbols> map, IIndexFileLocation location, - IASTPreprocessorStatement thing) { - Symbols lists= map.get(location); + private void addToMap(Map<IASTPreprocessorIncludeStatement, Symbols> symbolMap, + IASTPreprocessorIncludeStatement owner, IASTPreprocessorStatement thing) { + Symbols lists= symbolMap.get(owner); if (lists != null) lists.fMacros.add(thing); } - private boolean prepareInMap(Map<IIndexFileLocation, Symbols> map, IIndexFileLocation location) { - if (map.get(location) == null) { - map.put(location, new Symbols()); - } - return false; - } - - private IIndexFragmentFile storeFileInIndex(IWritableIndex index, IIndexFileLocation location, - Map<IIndexFileLocation, Symbols> symbolMap, int linkageID, long fileContentsHash, - int configHash, Set<IASTPreprocessorIncludeStatement> contextIncludes, + private IIndexFragmentFile storeFileInIndex(Data data, FileInAST astFile, int linkageID, YieldableIndexLock lock) throws CoreException, InterruptedException { - Set<IIndexFileLocation> clearedContexts= Collections.emptySet(); + final IWritableIndex index = data.fIndex; 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); - if (oldFile != null) { - IIndexInclude[] includedBy = index.findIncludedBy(oldFile); - if (includedBy.length > 0) { - clearedContexts= new HashSet<IIndexFileLocation>(); - for (IIndexInclude include : includedBy) { - clearedContexts.add(include.getIncludedByLocation()); - } - } - } - file= index.addUncommittedFile(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); + 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()][]); @@ -487,22 +538,30 @@ abstract public class PDOMWriter { } } - IncludeInformation[] includeInfos= new IncludeInformation[lists.fIncludes.size()]; + List<IncludeInformation> includeInfos= new ArrayList<IncludeInformation>(); for (int i= 0; i < lists.fIncludes.size(); i++) { - final IASTPreprocessorIncludeStatement include = lists.fIncludes.get(i); - final IncludeInformation info= includeInfos[i]= new IncludeInformation(); - info.fStatement= include; - if (include.isResolved()) { - info.fLocation= fResolver.resolveASTPath(include.getPath()); - info.fIsContext= include.isActive() && - (contextIncludes.contains(include) || clearedContexts.contains(info.fLocation)); + final IASTPreprocessorIncludeStatement stmt = lists.fIncludes.get(i); + if (!stmt.isResolved()) { + includeInfos.add(new IncludeInformation(stmt, null, ISignificantMacros.NONE, false)); + } else { + IIndexFileLocation targetLoc = fResolver.resolveASTPath(stmt.getPath()); + ISignificantMacros mainSig= stmt.getSignificantMacros(); + for (ISignificantMacros sig : stmt.getLoadedVersions()) { + if (!sig.equals(mainSig)) { + includeInfos.add(new IncludeInformation(stmt, targetLoc, sig, false)); + } + } + final boolean isContext = stmt.isActive() && stmt.isResolved() && + (data.fContextIncludes.contains(stmt) || isContextFor(oldFile, stmt)); + includeInfos.add(new IncludeInformation(stmt, targetLoc, mainSig, isContext)); } } - index.setFileContent(file, linkageID, includeInfos, macros, names, fResolver, lock); + IncludeInformation[] includeInfoArray= includeInfos.toArray(new IncludeInformation[includeInfos.size()]); + index.setFileContent(file, linkageID, includeInfoArray, macros, names, fResolver, lock); } file.setTimestamp(fResolver.getLastModified(location)); file.setEncodingHashcode(fResolver.getEncoding(location).hashCode()); - file.setContentsHash(fileContentsHash); + file.setContentsHash(astFile.fContentsHash); file = index.commitUncommittedFile(); } finally { index.clearUncommittedFile(); @@ -510,35 +569,21 @@ abstract public class PDOMWriter { return file; } - /** - * Makes a copy of the current progress information and returns it. - * @since 4.0 - */ - 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; + private boolean isContextFor(IIndexFragmentFile oldFile, IASTPreprocessorIncludeStatement stmt) + throws CoreException { + IIndexFile target= stmt.getImportedIndexFile(); + if (oldFile != null && target != null) { + IIndexInclude ctxInclude = target.getParsedInContext(); + if (ctxInclude != null && oldFile.equals(ctxInclude.getIncludedBy())) + return true; } + return false; } /** - * Updates current progress information with the provided delta. + * Informs the subclass that a file has been stored in the index. */ - protected final void incrementRequestedFilesCount(int delta) { - synchronized (fInfo) { - fInfo.fRequestedFilesCount += delta; - } - } + protected abstract void reportFileWrittenToIndex(FileInAST file, IIndexFragmentFile iFile) throws CoreException; 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..a339445fa7d 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 @@ -264,7 +264,7 @@ public class TeamPDOMImportOperation implements IWorkspaceRunnable { for (IIndexFragmentFile ifile : filesToDelete) { if (ifile != null) { checkMonitor(monitor); - pdom.clearFile(ifile, null); + pdom.clearFile(ifile); } } for (FileAndChecksum fc : updateTimestamps) { @@ -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..aa42326413f 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,32 +1,36 @@ /******************************************************************************* - * 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; import java.io.File; import java.util.ArrayList; -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.pdom.db.BTree; +import org.eclipse.cdt.internal.core.index.IWritableIndexFragment; import org.eclipse.cdt.internal.core.pdom.db.ChunkCache; import org.eclipse.cdt.internal.core.pdom.db.DBProperties; import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor; @@ -45,7 +49,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<String, IPDOMLinkageFactory> linkageFactoryMappings) throws CoreException { @@ -62,50 +66,50 @@ 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; if (fileBeingUpdated == null) { - // New file. - BTree fileIndex = getFileIndex(); - fileIndex.insert(uncommittedFile.getRecord()); + // New file, insert it into the index. file = uncommittedFile; + getFileIndex().insert(file.getRecord()); } else { // Existing file. fileBeingUpdated.replaceContentsFrom(uncommittedFile); file = fileBeingUpdated; fileBeingUpdated = null; } - fEvent.fFilesWritten.add(uncommittedLocation); + fEvent.fFilesWritten.add(uncommittedKey.getLocation()); uncommittedFile = null; - uncommittedLocation = null; + uncommittedKey = null; return file; } public void clearUncommittedFile() throws CoreException { if (uncommittedFile != null) { try { - uncommittedFile.clear(null); + uncommittedFile.clear(); uncommittedFile.delete(); } finally { uncommittedFile = null; - uncommittedLocation = null; + uncommittedKey = null; fileBeingUpdated = null; } } @@ -117,7 +121,6 @@ public class WritablePDOM extends PDOM implements IWritableIndexFragment { assert sourceFile.getIndexFragment() == this; PDOMFile pdomFile = (PDOMFile) sourceFile; - pdomFile.addIncludesTo(includes); pdomFile.addMacros(macros); final ASTFilePathResolver origResolver= fPathResolver; fPathResolver= pathResolver; @@ -126,6 +129,8 @@ public class WritablePDOM extends PDOM implements IWritableIndexFragment { } finally { fPathResolver= origResolver; } + // Includes expose the temporary file in the index, we must not yield the lock beyond this point. + pdomFile.addIncludesTo(includes); final IIndexFileLocation location = pdomFile.getLocation(); if (location != null) { @@ -134,12 +139,13 @@ public class WritablePDOM extends PDOM implements IWritableIndexFragment { } } - public void clearFile(IIndexFragmentFile file, Collection<IIndexFileLocation> contextsRemoved) - throws CoreException { + public void clearFile(IIndexFragmentFile file) 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(); + + fEvent.fClearedFiles.add(location); } @Override @@ -165,9 +171,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. * * <b>A write-lock must be obtained before calling this method</b> * @@ -202,7 +208,7 @@ public class WritablePDOM extends PDOM implements IWritableIndexFragment { // remove content where converter returns null for (PDOMFile file : notConverted) { file.convertIncludersToUnresolved(); - file.clear(null); + file.clear(); } } @@ -227,16 +233,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/YieldableIndexLock.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/YieldableIndexLock.java index c96636f81dd..03015c012c4 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/YieldableIndexLock.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/YieldableIndexLock.java @@ -19,14 +19,12 @@ import org.eclipse.cdt.internal.core.index.IWritableIndex; */ public class YieldableIndexLock { private final IWritableIndex index; - private final int readlockCount; private final boolean flushIndex; private long lastLockTime; private long cumulativeLockTime; - public YieldableIndexLock(IWritableIndex index, int readlockCount, boolean flushIndex) { + public YieldableIndexLock(IWritableIndex index, boolean flushIndex) { this.index = index; - this.readlockCount = readlockCount; this.flushIndex = flushIndex; } @@ -36,7 +34,7 @@ public class YieldableIndexLock { * @throws InterruptedException */ public void acquire() throws InterruptedException { - index.acquireWriteLock(readlockCount); + index.acquireWriteLock(); lastLockTime = System.currentTimeMillis(); } @@ -45,7 +43,7 @@ public class YieldableIndexLock { */ public void release() { if (lastLockTime != 0) { - index.releaseWriteLock(readlockCount, flushIndex); + index.releaseWriteLock(flushIndex); cumulativeLockTime += System.currentTimeMillis() - lastLockTime; lastLockTime = 0; } @@ -58,7 +56,7 @@ public class YieldableIndexLock { */ public void yield() throws InterruptedException { if (index.hasWaitingReaders()) { - index.releaseWriteLock(readlockCount, false); + index.releaseWriteLock(false); cumulativeLockTime += System.currentTimeMillis() - lastLockTime; lastLockTime = 0; acquire(); 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..dac2a04cdc1 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 @@ -16,7 +16,6 @@ package org.eclipse.cdt.internal.core.pdom.dom; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -31,18 +30,19 @@ import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IMacroBinding; import org.eclipse.cdt.core.dom.ast.IParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective; -import org.eclipse.cdt.core.index.IIndexFile; import org.eclipse.cdt.core.index.IIndexFileLocation; 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 +56,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 SignificantMacros are either final or atomically updated. 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 RECORD_SIZE= 56; + 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 FLAG_PRAGMA_ONCE_SEMANTICS = 0x01; public static class Comparator implements IBTreeComparator { private Database db; @@ -91,10 +94,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 +121,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 +131,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 +143,7 @@ public class PDOMFile implements IIndexFragmentFile { public PDOM getPDOM() { return fLinkage.getPDOM(); } - + @Override public boolean equals(Object obj) { if (obj == this) @@ -139,86 +159,45 @@ 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. * @throws CoreException */ public void replaceContentsFrom(PDOMFile sourceFile) throws CoreException { - ICPPUsingDirective[] directives= getUsingDirectives(); - for (ICPPUsingDirective ud : directives) { - if (ud instanceof IPDOMNode) { - ((IPDOMNode) ud).delete(null); - } - } - setFirstUsingDirectiveRec(sourceFile.getLastUsingDirectiveRec()); + // Delete current content + clear(); - // Replace the includes - PDOMInclude include = getFirstInclude(); - while (include != null) { - PDOMInclude nextInclude = include.getNextInIncludes(); - IIndexFile includedBy = include.getIncludedBy(); - if (this.equals(includedBy)) { - include.delete(); - } - include = nextInclude; - } - include = sourceFile.getFirstInclude(); + // Link in the using directives + setLastUsingDirective(sourceFile.getLastUsingDirectiveRec()); + + // Link in the includes, replace the owner. + PDOMInclude include = sourceFile.getFirstInclude(); setFirstInclude(include); - while (include != null) { - IIndexFile includedBy = include.getIncludedBy(); - if (sourceFile.equals(includedBy)) { - include.setIncludedBy(this); - if (sourceFile.equals(include.getIncludes())) { - include.setIncludes(this); - } - } - include = include.getNextInIncludes(); + for (; include != null; include= include.getNextInIncludes()) { + include.setIncludedBy(this); } - // Replace all the macros in this file. - PDOMLinkage linkage= getLinkage(); - PDOMMacro macro = getFirstMacro(); - while (macro != null) { - PDOMMacro nextMacro = macro.getNextMacro(); - macro.delete(linkage); - macro = nextMacro; - } - macro = sourceFile.getFirstMacro(); + // In the unexpected case that there is an included by relation, append it. + transferIncluders(sourceFile); + + // Link in the macros. + PDOMMacro macro = sourceFile.getFirstMacro(); setFirstMacro(macro); for (; macro != null; macro = macro.getNextMacro()) { macro.setFile(this); } - // Replace all macro references - ArrayList<PDOMMacroReferenceName> mrefs= new ArrayList<PDOMMacroReferenceName>(); - PDOMMacroReferenceName mref = getFirstMacroReference(); - while (mref != null) { - mrefs.add(mref); - mref= mref.getNextInFile(); - } - for (PDOMMacroReferenceName m : mrefs) { - m.delete(); - } - mref = sourceFile.getFirstMacroReference(); + // Link in macro references + PDOMMacroReferenceName mref = sourceFile.getFirstMacroReference(); setFirstMacroReference(mref); for (; mref != null; mref = mref.getNextInFile()) { mref.setFile(this); } // Replace all the names in this file - ArrayList<PDOMName> names= new ArrayList<PDOMName>(); - PDOMName name = getFirstName(); - for (; name != null; name= name.getNextInFile()) { - names.add(name); - linkage.onDeleteName(name); - } - for (Iterator<PDOMName> iterator = names.iterator(); iterator.hasNext();) { - name = iterator.next(); - name.delete(); - } - name = sourceFile.getFirstName(); + PDOMName name = sourceFile.getFirstName(); setFirstName(name); for (; name != null; name= name.getNextInFile()) { name.setFile(this); @@ -227,11 +206,58 @@ public class PDOMFile implements IIndexFragmentFile { setTimestamp(sourceFile.getTimestamp()); setEncodingHashcode(sourceFile.getEncodingHashcode()); setContentsHash(sourceFile.getContentsHash()); - setScannerConfigurationHashcode(sourceFile.getScannerConfigurationHashcode()); + // Transfer the flags. + Database db= fLinkage.getDB(); + db.putByte(record + FLAGS, db.getByte(sourceFile.record + FLAGS)); + + // Delete the source file sourceFile.delete(); } + public void transferIncluders(IIndexFragmentFile sourceFile) throws CoreException { + PDOMFile source= (PDOMFile) sourceFile; + PDOMInclude include = source.getFirstIncludedBy(); + if (include != null) { + // Detach the includes + source.setFirstIncludedBy(null); + // Adjust the includes + for (PDOMInclude i= include; i != null; i= i.getNextInIncludedBy()) { + i.setIncludes(this); + } + // Append the includes + PDOMInclude last= getFirstIncludedBy(); + if (last == null) { + setFirstIncludedBy(include); + } else { + for (PDOMInclude i= last; i != null; i= i.getNextInIncludedBy()) { + last= i; + } + last.setNextInIncludedBy(include); + include.setPrevInIncludedBy(last); + } + } + } + + public void transferContext(IIndexFragmentFile sourceFile) throws CoreException { + PDOMFile source= (PDOMFile) sourceFile; + PDOMInclude include = source.getFirstIncludedBy(); + if (include != null) { + // Detach the include + final PDOMInclude next = include.getNextInIncludedBy(); + include.setNextInIncludedBy(null); + source.setFirstIncludedBy(next); + if (next != null) + next.setPrevInIncludedBy(null); + + // Adjust the include + include.setIncludes(this); + + // Insert the include + addIncludedBy(include, false); + } + } + /** * This method should not be called on PDOMFile objects that are referenced by the file index. * @param location a new location @@ -239,9 +265,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 +287,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 +314,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 +327,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 +376,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(); } @@ -459,22 +495,22 @@ public class PDOMFile implements IIndexFragmentFile { return new PDOMMacroReferenceName(fLinkage, name, this, cont); } - public void clear(Collection<IIndexFileLocation> contextsRemoved) throws CoreException { + public void clear() throws CoreException { ICPPUsingDirective[] directives= getUsingDirectives(); for (ICPPUsingDirective ud : directives) { if (ud instanceof IPDOMNode) { ((IPDOMNode) ud).delete(null); } } - setFirstUsingDirectiveRec(0); + setLastUsingDirective(0); // Remove the includes PDOMInclude include = getFirstInclude(); while (include != null) { PDOMInclude nextInclude = include.getNextInIncludes(); - if (contextsRemoved != null && include.getPrevInIncludedByRecord() == 0) { - contextsRemoved.add(include.getIncludesLocation()); - } +// if (contextsRemoved != null && include.getPrevInIncludedByRecord() == 0) { +// contextsRemoved.add(include.getIncludesLocation()); +// } include.delete(); include = nextInclude; } @@ -515,7 +551,6 @@ public class PDOMFile implements IIndexFragmentFile { m.delete(); } setFirstMacroReference(null); - setTimestamp(-1); } @@ -529,6 +564,9 @@ public class PDOMFile implements IIndexFragmentFile { 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(); db.free(record); } @@ -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 IIndexFragmentFile[] 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(), null); + btree.accept(finder); + long[] records= finder.getRecords(); + IIndexFragmentFile[] result= new IIndexFragmentFile[records.length]; + for (int i = 0; i < result.length; i++) { + result[i]= new PDOMFile(linkage, records[i]); + } + return result; + } + return IIndexFragmentFile.EMPTY_ARRAY; + } + + /** + * 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 <code>null</code> 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()); + 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,17 @@ 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 hasContent() throws CoreException { return getTimestamp() != -1; } @@ -779,7 +886,7 @@ public class PDOMFile implements IIndexFragmentFile { return fLinkage.getDB().getRecPtr(record + LAST_USING_DIRECTIVE); } - public void setFirstUsingDirectiveRec(long rec) throws CoreException { + public void setLastUsingDirective(long rec) throws CoreException { fLinkage.getDB().putRecPtr(record + LAST_USING_DIRECTIVE, rec); } 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 eb3c04ceb0e..e11ac1d195b 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 @@ -890,7 +890,7 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants { long rec= file.getLastUsingDirectiveRec(); PDOMCPPUsingDirective ud= new PDOMCPPUsingDirective(this, rec, containerNS, pdomName.getBinding(), pdomName.getFileLocation().getNodeOffset()); - file.setFirstUsingDirectiveRec(ud.getRecord()); + file.setLastUsingDirective(ud.getRecord()); } } else if (parentNode instanceof ICPPASTElaboratedTypeSpecifier) { ICPPASTElaboratedTypeSpecifier elaboratedSpecifier = (ICPPASTElaboratedTypeSpecifier)parentNode; @@ -983,23 +983,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..cd99d472626 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 @@ -15,37 +15,25 @@ import java.util.Arrays; import java.util.Calendar; import java.util.Comparator; import java.util.HashSet; -import java.util.Map; import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.dom.ILinkage; import org.eclipse.cdt.core.dom.IPDOMIndexer; import org.eclipse.cdt.core.dom.IPDOMIndexerTask; import org.eclipse.cdt.core.index.IIndexManager; -import org.eclipse.cdt.core.model.AbstractLanguage; import org.eclipse.cdt.core.model.ICProject; -import org.eclipse.cdt.core.model.ILanguage; import org.eclipse.cdt.core.model.ITranslationUnit; -import org.eclipse.cdt.core.model.LanguageManager; -import org.eclipse.cdt.core.parser.IScannerInfo; -import org.eclipse.cdt.core.parser.IScannerInfoProvider; -import org.eclipse.cdt.core.parser.ScannerInfo; import org.eclipse.cdt.internal.core.index.IWritableIndex; import org.eclipse.cdt.internal.core.index.IWritableIndexManager; import org.eclipse.cdt.internal.core.pdom.AbstractIndexerTask; import org.eclipse.cdt.internal.core.pdom.ITodoTaskUpdater; import org.eclipse.cdt.internal.core.pdom.IndexerProgress; import org.eclipse.cdt.internal.core.pdom.db.ChunkCache; -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; import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.content.IContentType; import org.eclipse.osgi.util.NLS; import com.ibm.icu.text.NumberFormat; @@ -177,59 +165,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(); - IContentType ct= CCorePlugin.getContentType(project, filename); - if (ct != null) { - ILanguage l = LanguageManager.getInstance().getLanguage(ct, project); - if (l instanceof AbstractLanguage) { - if (filename.indexOf('.') >= 0 && ct.getId().equals(CCorePlugin.CONTENT_TYPE_CXXHEADER) && - l.getLinkageID() == ILinkage.CPP_LINKAGE_ID) { - ILanguage l2= LanguageManager.getInstance().getLanguageForContentTypeID(CCorePlugin.CONTENT_TYPE_CHEADER); - if (l2 instanceof AbstractLanguage) { - return new AbstractLanguage[] {(AbstractLanguage) l, (AbstractLanguage) l2}; - } - } - return new AbstractLanguage[] {(AbstractLanguage) l}; - } - } - return new AbstractLanguage[0]; - } - - @Override - protected IScannerInfo createDefaultScannerConfig(int linkageID) { - IProject project= getProject().getProject(); - IScannerInfoProvider provider= CCorePlugin.getDefault().getScannerInfoProvider(project); - IScannerInfo scanInfo; - if (provider != null) { - String filename= linkageID == ILinkage.C_LINKAGE_ID ? "__cdt__.c" : "__cdt__.cpp"; //$NON-NLS-1$//$NON-NLS-2$ - IFile file= project.getFile(filename); - scanInfo= provider.getScannerInformation(file); - if (scanInfo == null || scanInfo.getDefinedSymbols().isEmpty()) { - scanInfo= provider.getScannerInformation(project); - } - if (linkageID == ILinkage.C_LINKAGE_ID) { - final Map<String, String> definedSymbols = scanInfo.getDefinedSymbols(); - definedSymbols.remove("__cplusplus__"); //$NON-NLS-1$ - definedSymbols.remove("__cplusplus"); //$NON-NLS-1$ - } - } else { - scanInfo= new ScannerInfo(); - } - return scanInfo; - } - private ICProject getProject() { return getIndexer().getProject(); } @@ -406,4 +341,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/parser/org/eclipse/cdt/internal/core/pdom/indexer/PDOMRebuildTask.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/PDOMRebuildTask.java index 9c93a98cae3..37f82a39365 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/PDOMRebuildTask.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/PDOMRebuildTask.java @@ -88,7 +88,7 @@ public class PDOMRebuildTask implements IPDOMIndexerTask { private void clearIndex(ICProject project, IWritableIndex index) throws CoreException, InterruptedException { // First clear the pdom - index.acquireWriteLock(0); + index.acquireWriteLock(); try { index.clear(); IWritableIndexFragment wf= index.getWritableFragment(); @@ -96,7 +96,7 @@ public class PDOMRebuildTask implements IPDOMIndexerTask { PDOMManager.writeProjectPDOMProperties((WritablePDOM) wf, project.getProject()); } } finally { - index.releaseWriteLock(0); + index.releaseWriteLock(); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/ProjectIndexerInputAdapter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/ProjectIndexerInputAdapter.java index 2c712127471..85a503c9141 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/ProjectIndexerInputAdapter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/ProjectIndexerInputAdapter.java @@ -146,7 +146,7 @@ public class ProjectIndexerInputAdapter extends IndexerInputAdapter { public String getASTPath(IIndexFileLocation ifl) { IPath path= IndexLocationFactory.getAbsolutePath(ifl); if (path != null) { - return path.toString(); + return path.toOSString(); } return ifl.getURI().getPath(); } 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) { diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/includebrowser/BasicIncludeBrowserTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/includebrowser/BasicIncludeBrowserTest.java index 6c82b07a5bf..f5174157a6a 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/includebrowser/BasicIncludeBrowserTest.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/includebrowser/BasicIncludeBrowserTest.java @@ -16,6 +16,7 @@ import junit.framework.Test; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeItem; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IPDOMManager; @@ -37,6 +38,7 @@ public class BasicIncludeBrowserTest extends IncludeBrowserBaseTest { // // source // #include "user.h" // #include <system.h> + // #include "user.h" public void testSimpleInclusion() throws Exception { TestScannerProvider.sIncludes= new String[] { getProject().getProject().getLocation().toOSString() }; @@ -50,9 +52,10 @@ public class BasicIncludeBrowserTest extends IncludeBrowserBaseTest { openIncludeBrowser(source); Tree tree = getIBTree(); - checkTreeNode(tree, 0, "source.cpp"); + TreeItem node = checkTreeNode(tree, 0, "source.cpp"); checkTreeNode(tree, 0, 0, "user.h"); checkTreeNode(tree, 0, 1, "system.h"); + assertEquals(2, node.getItemCount()); // The tree has to be reversed openIncludeBrowser(user, true); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/actions/CreateParserLogAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/actions/CreateParserLogAction.java index bd047e26758..245816efe30 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/actions/CreateParserLogAction.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/actions/CreateParserLogAction.java @@ -15,11 +15,13 @@ import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; import java.util.Comparator; +import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.SortedMap; import java.util.SortedSet; import java.util.TreeMap; @@ -42,6 +44,7 @@ import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.ILinkage; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; @@ -55,12 +58,14 @@ 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.index.IIndexInclude; +import org.eclipse.cdt.core.index.IndexLocationFactory; import org.eclipse.cdt.core.model.CModelException; +import org.eclipse.cdt.core.model.CoreModelUtil; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.model.ILanguage; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.parser.ExtendedScannerInfo; -import org.eclipse.cdt.core.parser.IScannerInfoProvider; +import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager; @@ -76,6 +81,7 @@ import org.eclipse.cdt.internal.ui.editor.ASTProvider; @SuppressWarnings("nls") public class CreateParserLogAction implements IObjectActionDelegate { + private static final String INDENT = " "; private static final class MyVisitor extends ASTVisitor { List<IASTProblem> fProblems= new ArrayList<IASTProblem>(); @@ -118,6 +124,8 @@ public class CreateParserLogAction implements IObjectActionDelegate { private ISelection fSelection; private IWorkbenchPartSite fSite; + + private boolean fWroteUnresolvedTitle; public void setActivePart(IAction action, IWorkbenchPart targetPart) { fSite= targetPart.getSite(); @@ -209,81 +217,90 @@ public class CreateParserLogAction implements IObjectActionDelegate { IStatus status = Status.OK_STATUS; final ICProject cproject = tu.getCProject(); final String projectName= cproject == null ? null : cproject.getElementName(); - String scannerInfoProvider= "null"; - if (cproject != null) { - IScannerInfoProvider provider = CCorePlugin.getDefault().getScannerInfoProvider(cproject.getProject()); - if (provider != null) { - scannerInfoProvider= provider.getClass().getName(); - } - } - - ITranslationUnit ctx= tu; + final IIndex index = ast.getIndex(); + + ITranslationUnit configureWith = tu; + int ctxLinkage= 0; + ISignificantMacros ctxSigMacros= null; if (tu instanceof TranslationUnit) { TranslationUnit itu= (TranslationUnit) tu; - ctx= itu.getSourceContextTU(ast.getIndex(), ITranslationUnit.AST_CONFIGURE_USING_SOURCE_CONTEXT); + IIndexFile[] ctxToHeader = itu.getContextToHeader(index, ITranslationUnit.AST_CONFIGURE_USING_SOURCE_CONTEXT); + if (ctxToHeader != null) { + try { + final IIndexFile ctxFile = ctxToHeader[0]; + ctxLinkage= ctxToHeader[0].getLinkageID(); + ctxSigMacros= ctxFile.getSignificantMacros(); + configureWith = CoreModelUtil.findTranslationUnitForLocation(ctxFile.getLocation(), cproject); + } catch (CoreException e) { + } + if (configureWith == null) { + configureWith= tu; + ctxToHeader= null; + } + } } - final ExtendedScannerInfo scfg= new ExtendedScannerInfo(ctx.getScannerInfo(true)); - final String indent= " "; + + final ExtendedScannerInfo scfg= new ExtendedScannerInfo(configureWith.getScannerInfo(true)); final MyVisitor visitor= new MyVisitor(); ast.accept(visitor); out.println("Project: " + projectName); + out.println("File: " + tu.getLocationURI()); + out.println("Language: " + lang.getName()); out.println("Index Version: " + PDOM.versionString(PDOM.getDefaultVersion())); - out.println("Scanner Info Provider: " + scannerInfoProvider); out.println("Build Configuration: " + getBuildConfig(cproject)); - out.println("File: " + tu.getLocationURI()); - out.println("Context: " + ctx.getLocationURI()); - out.println("Language: " + lang.getName()); - out.println(); - out.println("Include Search Path (option -I):"); - output(out, indent, scfg.getIncludePaths()); - out.println(); - out.println("Local Include Search Path (option -iquote):"); - output(out, indent, scfg.getLocalIncludePath()); - out.println(); - out.println("Preincluded files (option -include):"); - output(out, indent, scfg.getIncludeFiles()); - out.println(); - out.println("Preincluded macro files (option -imacros):"); - output(out, indent, scfg.getMacroFiles()); - out.println(); - out.println("Macro definitions (option -D):"); - HashSet<String> reported= new HashSet<String>(); - output(out, indent, scfg.getDefinedSymbols(), reported); - out.println(); - out.println("Macro definitions (from configuration + headers in index):"); - output(out, indent, ast.getBuiltinMacroDefinitions(), reported); - out.println(); - out.println("Macro definitions (from files actually parsed):"); - output(out, indent, ast.getMacroDefinitions(), reported); - - out.println(); - out.println("Unresolved includes (from headers in index):"); + if (configureWith == tu) { + out.println("Context: none"); + } else { + out.println("Context: " + configureWith.getLocationURI()); + out.println(INDENT + getLinkageName(ctxLinkage) + ", " + ctxSigMacros); + } + try { - outputUnresolvedIncludes(cproject, ast.getIndex(), out, indent, ast.getIncludeDirectives(), ast.getLinkage().getLinkageID()); + IIndexFile[] versions= index.getFiles(IndexLocationFactory.getIFL(tu)); + out.println("Versions in Index: " + versions.length); + for (IIndexFile f : versions) { + out.println(INDENT + getLinkageName(f.getLinkageID()) + ": " + f.getSignificantMacros()); + } } catch (CoreException e) { status= e.getStatus(); } - out.println(); - out.println("Scanner problems:"); - output(out, indent, ast.getPreprocessorProblems()); - out.println(); - out.println("Parser problems:"); - output(out, indent, visitor.fProblems.toArray(new IASTProblem[visitor.fProblems.size()])); + output(out, "Include Search Path (option -I):", scfg.getIncludePaths()); + output(out, "Local Include Search Path (option -iquote):", scfg.getLocalIncludePath()); + output(out, "Preincluded files (option -include):", scfg.getIncludeFiles()); + output(out, "Preincluded macro files (option -imacros):", scfg.getMacroFiles()); - out.println(); - out.println("Unresolved names:"); - output(out, indent, visitor.fProblemBindings); - - out.println(); - out.println("Exceptions in name resolution:"); - output(out, visitor.fExceptions); + HashSet<String> reported= new HashSet<String>(); + output(out, "Macro definitions (option -D):", scfg.getDefinedSymbols(), reported); + output(out, "Macro definitions (from language + headers in index):", ast.getBuiltinMacroDefinitions(), reported); + output(out, "Macro definitions (from files actually parsed):", ast.getMacroDefinitions(), reported); + try { + outputUnresolvedIncludes(cproject, ast.getIndex(), out, ast.getIncludeDirectives(), ast.getLinkage().getLinkageID()); + } catch (CoreException e) { + status= e.getStatus(); + } + output(out, "Scanner problems:", ast.getPreprocessorProblems()); + output(out, "Parser problems:", visitor.fProblems.toArray(new IASTProblem[0])); + output(out, "Unresolved names:", visitor.fProblemBindings.toArray(new IProblemBinding[0])); + output(out, "Exceptions in name resolution:", visitor.fExceptions); + out.println("Written on " + new Date().toString()); return status; } + private String getLinkageName(int linkageID) { + switch(linkageID) { + case ILinkage.NO_LINKAGE_ID: return ILinkage.NO_LINKAGE_NAME; + case ILinkage.C_LINKAGE_ID: return ILinkage.C_LINKAGE_NAME; + case ILinkage.CPP_LINKAGE_ID: return ILinkage.CPP_LINKAGE_NAME; + case ILinkage.FORTRAN_LINKAGE_ID: return ILinkage.FORTRAN_LINKAGE_NAME; + case ILinkage.OBJC_LINKAGE_ID: return ILinkage.OBJC_LINKAGE_NAME; + } + return String.valueOf(linkageID); + } + private String getBuildConfig(ICProject cproject) { ICProjectDescriptionManager prjDescMgr= CCorePlugin.getDefault().getProjectDescriptionManager(); ICProjectDescription prefs= prjDescMgr.getProjectDescription(cproject.getProject(), false); @@ -295,35 +312,37 @@ public class CreateParserLogAction implements IObjectActionDelegate { return "unknown"; } - private void outputUnresolvedIncludes(ICProject prj, IIndex index, PrintStream out, String indent, + private void outputUnresolvedIncludes(ICProject prj, IIndex index, PrintStream out, IASTPreprocessorIncludeStatement[] includeDirectives, int linkageID) throws CoreException { + fWroteUnresolvedTitle= false; ASTFilePathResolver resolver= new ProjectIndexerInputAdapter(prj); - HashSet<IIndexFileLocation> handled= new HashSet<IIndexFileLocation>(); + HashSet<IIndexFile> handled= new HashSet<IIndexFile>(); for (IASTPreprocessorIncludeStatement include : includeDirectives) { - if (include.isActive() && include.isResolved()) { - outputUnresolvedIncludes(index, out, indent, resolver.resolveASTPath(include.getPath()), linkageID, handled); + if (include.isResolved()) { + IIndexFileLocation ifl = resolver.resolveASTPath(include.getPath()); + IIndexFile ifile= index.getFile(linkageID, ifl, include.getSignificantMacros()); + outputUnresolvedIncludes(index, out, ifl, ifile, handled); } } + if (fWroteUnresolvedTitle) + out.println(); } - private void outputUnresolvedIncludes(IIndex index, PrintStream out, String indent, - IIndexFileLocation ifl, int linkageID, HashSet<IIndexFileLocation> handled) throws CoreException { - if (!handled.add(ifl)) { - return; - } - IIndexFile ifile= index.getFile(linkageID, ifl); + private void outputUnresolvedIncludes(IIndex index, PrintStream out, + IIndexFileLocation ifl, IIndexFile ifile, Set<IIndexFile> handled) throws CoreException { if (ifile == null) { - out.println(indent + ifl.getURI() + " is not indexed"); - } - else { + writeUnresolvedTitle(out); + out.println(INDENT + ifl.getURI() + " is not indexed"); + } else if (handled.add(ifile)) { IIndexInclude[] includes = ifile.getIncludes(); for (IIndexInclude inc : includes) { if (inc.isActive()) { if (inc.isResolved()) { - outputUnresolvedIncludes(index, out, indent, inc.getIncludesLocation(), linkageID, handled); - } - else { - out.println(indent + "Unresolved inclusion: " + inc.getFullName() + " in file " + + IIndexFile next = index.resolveInclude(inc); + outputUnresolvedIncludes(index, out, inc.getIncludesLocation(), next, handled); + } else { + writeUnresolvedTitle(out); + out.println(INDENT + "Unresolved inclusion: " + inc.getFullName() + " in file " + inc.getIncludedByLocation().getURI()); } } @@ -331,53 +350,85 @@ public class CreateParserLogAction implements IObjectActionDelegate { } } - private void output(PrintStream out, String indent, String[] list) { - for (String line : list) { - out.println(indent + line); + public void writeUnresolvedTitle(PrintStream out) { + if (!fWroteUnresolvedTitle) { + fWroteUnresolvedTitle= true; + out.println("Unresolved includes (from headers in index):"); } } - private void output(PrintStream out, String indent, Map<String, String> definedSymbols, HashSet<String> reported) { - SortedMap<String, String> sorted= new TreeMap<String, String>(COMP_INSENSITIVE); - sorted.putAll(definedSymbols); - for (Entry<String, String> entry : sorted.entrySet()) { - final String macro = entry.getKey() + '=' + entry.getValue(); - if (reported.add(macro)) { - out.println(indent + macro); + private void output(PrintStream out, String label, String[] list) { + if (list.length > 0) { + out.println(label); + for (String line : list) { + out.println(INDENT + line); } + out.println(); } } - - private void output(PrintStream out, String indent, IASTPreprocessorMacroDefinition[] defs, HashSet<String> reported) { - SortedSet<String> macros= new TreeSet<String>(COMP_INSENSITIVE); - for (IASTPreprocessorMacroDefinition def : defs) { - macros.add(def.toString()); - } - - for (String macro : macros) { - if (reported.add(macro)) { - out.println(indent + macro); + + private void output(PrintStream out, String label, Map<String, String> definedSymbols, HashSet<String> reported) { + if (!definedSymbols.isEmpty()) { + out.println(label); + + SortedMap<String, String> sorted= new TreeMap<String, String>(COMP_INSENSITIVE); + sorted.putAll(definedSymbols); + for (Entry<String, String> entry : sorted.entrySet()) { + final String macro = entry.getKey() + '=' + entry.getValue(); + if (reported.add(macro)) { + out.println(INDENT + macro); + } } + out.println(); } } - private void output(PrintStream out, String indent, IASTProblem[] preprocessorProblems) { - for (IASTProblem problem : preprocessorProblems) { - out.println(indent + problem.getMessageWithLocation()); + private void output(PrintStream out, String label, IASTPreprocessorMacroDefinition[] defs, HashSet<String> reported) { + if (defs.length > 0) { + out.println(label); + SortedSet<String> macros= new TreeSet<String>(COMP_INSENSITIVE); + for (IASTPreprocessorMacroDefinition def : defs) { + macros.add(def.toString()); + } + + for (String macro : macros) { + if (reported.add(macro)) { + out.println(INDENT + macro); + } + } + out.println(); } } - private void output(PrintStream out, String indent, List<IProblemBinding> list) { - for (IProblemBinding problem : list) { - String file= problem.getFileName(); - int line = problem.getLineNumber(); - out.println(indent + problem.getMessage() + " in file " + file + ':' + line); + private void output(PrintStream out, String label, IASTProblem[] preprocessorProblems) { + if (preprocessorProblems.length > 0) { + out.println(label); + for (IASTProblem problem : preprocessorProblems) { + out.println(INDENT + problem.getMessageWithLocation()); + } + out.println(); + } + } + + private void output(PrintStream out, String label, IProblemBinding[] list) { + if (list.length > 0) { + out.println(label); + for (IProblemBinding problem : list) { + String file= problem.getFileName(); + int line = problem.getLineNumber(); + out.println(INDENT + problem.getMessage() + " in file " + file + ':' + line); + } + out.println(); } } - private void output(PrintStream out, List<Exception> list) { - for (Exception problem : list) { - problem.printStackTrace(out); + private void output(PrintStream out, String label, List<Exception> list) { + if (!list.isEmpty()) { + out.println(label); + for (Exception problem : list) { + problem.printStackTrace(out); + } + out.println(); } } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/includebrowser/IBContentProvider.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/includebrowser/IBContentProvider.java index 6c92fbf840e..96a8383a060 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/includebrowser/IBContentProvider.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/includebrowser/IBContentProvider.java @@ -12,6 +12,8 @@ package org.eclipse.cdt.internal.ui.includebrowser; import java.util.ArrayList; import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; @@ -102,7 +104,7 @@ public class IBContentProvider extends AsyncTreeContentProvider { directiveFile= node.getRepresentedFile(); } if (includes.length > 0) { - ArrayList<IBNode> result= new ArrayList<IBNode>(includes.length); + Set<IBNode> result= new LinkedHashSet<IBNode>(includes.length); for (int i = 0; i < includes.length; i++) { IIndexInclude include = includes[i]; try { @@ -122,7 +124,8 @@ public class IBContentProvider extends AsyncTreeContentProvider { include.getIncludedBy().getTimestamp()); newnode.setIsActiveCode(include.isActive()); newnode.setIsSystemInclude(include.isSystemInclude()); - result.add(newnode); + if (!result.contains(newnode) || newnode.isActiveCode()) + result.add(newnode); } catch (CoreException e) { CUIPlugin.log(e); } |