diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Actions/FoldActions.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Actions/FoldActions.cs index 47dbdc610b..1f6643836f 100644 --- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Actions/FoldActions.cs +++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Actions/FoldActions.cs @@ -9,15 +9,29 @@ using System; using System.Collections.Generic; using ICSharpCode.TextEditor.Document; -namespace ICSharpCode.TextEditor.Actions +namespace ICSharpCode.TextEditor.Actions { public class ToggleFolding : AbstractEditAction { public override void Execute(TextArea textArea) { List foldMarkers = textArea.Document.FoldingManager.GetFoldingsWithStart(textArea.Caret.Line); - foreach (FoldMarker fm in foldMarkers) { - fm.IsFolded = !fm.IsFolded; + if (foldMarkers.Count != 0) { + foreach (FoldMarker fm in foldMarkers) + fm.IsFolded = !fm.IsFolded; + } else { + foldMarkers = textArea.Document.FoldingManager.GetFoldingsContainsLineNumber(textArea.Caret.Line); + if (foldMarkers.Count != 0) { + FoldMarker innerMost = foldMarkers[0]; + for (int i = 1; i < foldMarkers.Count; i++) { + if (new TextLocation(foldMarkers[i].StartColumn, foldMarkers[i].StartLine) > + new TextLocation(innerMost.StartColumn, innerMost.StartLine)) + { + innerMost = foldMarkers[i]; + } + } + innerMost.IsFolded = !innerMost.IsFolded; + } } textArea.Document.FoldingManager.NotifyFoldingsChanged(EventArgs.Empty); } diff --git a/src/Libraries/NRefactory/Project/NRefactory.csproj b/src/Libraries/NRefactory/Project/NRefactory.csproj index 0b1dfee10c..fa7e95ad27 100644 --- a/src/Libraries/NRefactory/Project/NRefactory.csproj +++ b/src/Libraries/NRefactory/Project/NRefactory.csproj @@ -55,6 +55,7 @@ + diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs b/src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs index 1fc7d608a5..a5f62b1508 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs @@ -40,15 +40,10 @@ namespace ICSharpCode.NRefactory.Parser // used for the original value of strings (with escape sequences). protected StringBuilder originalValue = new StringBuilder(); - bool skipAllComments = false; - - public bool SkipAllComments { - get { - return skipAllComments; - } - set { - skipAllComments = value; - } + public bool SkipAllComments { get; set; } + public bool EvaluateConditionalCompilation { get; set; } + public virtual IDictionary ConditionalCompilationSymbols { + get { throw new NotSupportedException(); } } protected int Line { diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/ConditionalCompilation.cs b/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/ConditionalCompilation.cs new file mode 100644 index 0000000000..3b45a985c3 --- /dev/null +++ b/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/ConditionalCompilation.cs @@ -0,0 +1,90 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Visitors; + +namespace ICSharpCode.NRefactory.Parser.CSharp +{ + sealed class ConditionalCompilation : AbstractAstVisitor + { + static readonly object SymbolDefined = new object(); + Dictionary symbols = new Dictionary(); + + public IDictionary Symbols { + get { return symbols; } + } + + public void Define(string symbol) + { + symbols[symbol] = SymbolDefined; + } + + public void Undefine(string symbol) + { + symbols.Remove(symbol); + } + + public bool Evaluate(Expression condition) + { + return condition.AcceptVisitor(this, null) == SymbolDefined; + } + + public override object VisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data) + { + if (primitiveExpression.Value is bool) + return (bool)primitiveExpression.Value ? SymbolDefined : null; + else + return null; + } + + public override object VisitIdentifierExpression(IdentifierExpression identifierExpression, object data) + { + return symbols.ContainsKey(identifierExpression.Identifier) ? SymbolDefined : null; + } + + public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data) + { + if (unaryOperatorExpression.Op == UnaryOperatorType.Not) { + return unaryOperatorExpression.Expression.AcceptVisitor(this, data) == SymbolDefined ? null : SymbolDefined; + } else { + return null; + } + } + + public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data) + { + bool lhs = binaryOperatorExpression.Left.AcceptVisitor(this, data) == SymbolDefined; + bool rhs = binaryOperatorExpression.Right.AcceptVisitor(this, data) == SymbolDefined; + bool result; + switch (binaryOperatorExpression.Op) { + case BinaryOperatorType.LogicalAnd: + result = lhs && rhs; + break; + case BinaryOperatorType.LogicalOr: + result = lhs || rhs; + break; + case BinaryOperatorType.Equality: + result = lhs == rhs; + break; + case BinaryOperatorType.InEquality: + result = lhs != rhs; + break; + default: + return null; + } + return result ? SymbolDefined : null; + } + + public override object VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data) + { + return parenthesizedExpression.Expression.AcceptVisitor(this, data); + } + } +} diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs b/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs index 477eeb23b8..503bb97786 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs @@ -6,6 +6,7 @@ // using System; +using System.Collections.Generic; using System.Globalization; using System.IO; using System.Text; @@ -18,20 +19,6 @@ namespace ICSharpCode.NRefactory.Parser.CSharp { } - void ReadPreProcessingDirective() - { - Location start = new Location(Col - 1, Line); - - // skip spaces between # and the directive - while (ReaderPeek() == ' ') - ReaderRead(); - - bool canBeKeyword; - string directive = ReadIdent('#', out canBeKeyword); - string argument = ReadToEndOfLine(); - this.specialTracker.AddPreprocessingDirective(directive, argument.Trim(), start, new Location(start.X + directive.Length + argument.Length, start.Y)); - } - protected override Token Next() { int nextChar; @@ -974,5 +961,211 @@ namespace ICSharpCode.NRefactory.Parser.CSharp } curToken = new Token(Tokens.EOF, Col, Line); } + + public override IDictionary ConditionalCompilationSymbols { + get { return conditionalCompilation.Symbols; } + } + + ConditionalCompilation conditionalCompilation = new ConditionalCompilation(); + + void ReadPreProcessingDirective() + { + PreprocessingDirective d = ReadPreProcessingDirectiveInternal(true, true); + this.specialTracker.AddPreprocessingDirective(d); + + if (EvaluateConditionalCompilation) { + switch (d.Cmd) { + case "#define": + conditionalCompilation.Define(d.Arg); + break; + case "#undef": + conditionalCompilation.Undefine(d.Arg); + break; + case "#if": + if (!conditionalCompilation.Evaluate(d.Expression)) { + // skip to valid #elif or #else or #endif + int level = 1; + while (true) { + d = SkipToPreProcessingDirective(false, level == 1); + if (d == null) + break; + if (d.Cmd == "#if") { + level++; + } else if (d.Cmd == "#endif") { + level--; + if (level == 0) + break; + } else if (level == 1 && (d.Cmd == "#else" + || d.Cmd == "#elif" && conditionalCompilation.Evaluate(d.Expression))) + { + break; + } + } + if (d != null) + this.specialTracker.AddPreprocessingDirective(d); + } + break; + case "#elif": + case "#else": + // we already visited the #if part or a previous #elif part, so skip until #endif + { + int level = 1; + while (true) { + d = SkipToPreProcessingDirective(false, false); + if (d == null) + break; + if (d.Cmd == "#if") { + level++; + } else if (d.Cmd == "#endif") { + level--; + if (level == 0) + break; + } + } + if (d != null) + this.specialTracker.AddPreprocessingDirective(d); + } + break; + } + } + } + + PreprocessingDirective SkipToPreProcessingDirective(bool parseIfExpression, bool parseElifExpression) + { + int c; + while (true) { + PPWhitespace(); + c = ReaderRead(); + if (c == -1) { + errors.Error(Line, Col, String.Format("Reached EOF but expected #endif")); + return null; + } else if (c == '#') { + break; + } else { + SkipToEndOfLine(); + } + } + return ReadPreProcessingDirectiveInternal(parseIfExpression, parseElifExpression); + } + + PreprocessingDirective ReadPreProcessingDirectiveInternal(bool parseIfExpression, bool parseElifExpression) + { + Location start = new Location(Col - 1, Line); + + // skip spaces between # and the directive + PPWhitespace(); + + bool canBeKeyword; + string directive = ReadIdent('#', out canBeKeyword); + + PPWhitespace(); + if (parseIfExpression && directive == "#if" || parseElifExpression && directive == "#elif") { + Ast.Expression expr = PPExpression(); + int c = ReaderRead(); + if (c >= 0 && !HandleLineEnd((char)c)) { + if (c == '/' && ReaderRead() == '/') { + // comment to end of line + } else { + errors.Error(Col, Line, "Expected end of line"); + } + SkipToEndOfLine(); // skip comment + } + return new PreprocessingDirective(directive, null, start, new Location(Col, Line)) { Expression = expr }; + } else { + string arg = ReadToEndOfLine(); + int pos = arg.IndexOf("//"); + if (pos >= 0) + arg = arg.Substring(0, pos); + arg = arg.Trim(); + return new PreprocessingDirective(directive, arg, start, new Location(Col, Line)); + } + } + + void PPWhitespace() + { + while (ReaderPeek() == ' ' || ReaderPeek() == '\t') + ReaderRead(); + } + + Ast.Expression PPExpression() + { + Ast.Expression expr = PPAndExpression(); + while (ReaderPeek() == '|') { + Token token = ReadOperator((char)ReaderRead()); + if (token == null || token.kind != Tokens.LogicalOr) { + return expr; + } + Ast.Expression expr2 = PPAndExpression(); + expr = new Ast.BinaryOperatorExpression(expr, Ast.BinaryOperatorType.LogicalOr, expr2); + } + return expr; + } + + Ast.Expression PPAndExpression() + { + Ast.Expression expr = PPEqualityExpression(); + while (ReaderPeek() == '&') { + Token token = ReadOperator((char)ReaderRead()); + if (token == null || token.kind != Tokens.LogicalAnd) { + break; + } + Ast.Expression expr2 = PPEqualityExpression(); + expr = new Ast.BinaryOperatorExpression(expr, Ast.BinaryOperatorType.LogicalAnd, expr2); + } + return expr; + } + + Ast.Expression PPEqualityExpression() + { + Ast.Expression expr = PPUnaryExpression(); + while (ReaderPeek() == '=' || ReaderPeek() == '!') { + Token token = ReadOperator((char)ReaderRead()); + if (token == null || token.kind != Tokens.Equals && token.kind != Tokens.NotEqual) { + break; + } + Ast.Expression expr2 = PPUnaryExpression(); + expr = new Ast.BinaryOperatorExpression(expr, token.kind == Tokens.Equals ? Ast.BinaryOperatorType.Equality : Ast.BinaryOperatorType.InEquality, expr2); + } + return expr; + } + + Ast.Expression PPUnaryExpression() + { + PPWhitespace(); + if (ReaderPeek() == '!') { + ReaderRead(); + PPWhitespace(); + return new Ast.UnaryOperatorExpression(PPUnaryExpression(), Ast.UnaryOperatorType.Not); + } else { + return PPPrimaryExpression(); + } + } + + Ast.Expression PPPrimaryExpression() + { + int c = ReaderRead(); + if (c < 0) + return Ast.Expression.Null; + if (c == '(') { + Ast.Expression expr = new Ast.ParenthesizedExpression(PPExpression()); + PPWhitespace(); + if (ReaderRead() != ')') + errors.Error(Col, Line, "Expected ')'"); + PPWhitespace(); + return expr; + } else { + if (c != '_' && !char.IsLetterOrDigit((char)c) && c != '\\') + errors.Error(Col, Line, "Expected conditional symbol"); + bool canBeKeyword; + string symbol = ReadIdent((char)c, out canBeKeyword); + PPWhitespace(); + if (canBeKeyword && symbol == "true") + return new Ast.PrimitiveExpression(true, "true"); + else if (canBeKeyword && symbol == "false") + return new Ast.PrimitiveExpression(false, "false"); + else + return new Ast.IdentifierExpression(symbol); + } + } } } diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/ILexer.cs b/src/Libraries/NRefactory/Project/Src/Lexer/ILexer.cs index f27f0f6d70..ab647b75f6 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/ILexer.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/ILexer.cs @@ -50,6 +50,17 @@ namespace ICSharpCode.NRefactory.Parser set; } + /// + /// Gets/Sets if the lexer should evaluate conditional compilation symbols. + /// + bool EvaluateConditionalCompilation { get; set; } + + /// + /// The dictionary with the conditional compilation symbols. + /// C# ignores the value (you can use null), it just cares whether a symbol is defined. + /// + IDictionary ConditionalCompilationSymbols { get; } + /// /// Returns the comments that had been read and containing tag key words. /// @@ -75,7 +86,7 @@ namespace ICSharpCode.NRefactory.Parser /// An object. Token NextToken(); - /// + /// /// Skips to the end of the current code block. /// For this, the lexer must have read the next token AFTER the token opening the /// block (so that Lexer.Token is the block-opening token, not Lexer.LookAhead). diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/Special/ISpecial.cs b/src/Libraries/NRefactory/Project/Src/Lexer/Special/ISpecial.cs index 5e83522c62..b610828384 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/Special/ISpecial.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/Special/ISpecial.cs @@ -32,37 +32,20 @@ namespace ICSharpCode.NRefactory { public abstract object AcceptVisitor(ISpecialVisitor visitor, object data); - Location startPosition, endPosition; - protected AbstractSpecial(Location position) { - this.startPosition = position; - this.endPosition = position; + this.StartPosition = position; + this.EndPosition = position; } protected AbstractSpecial(Location startPosition, Location endPosition) { - this.startPosition = startPosition; - this.endPosition = endPosition; - } - - public Location StartPosition { - get { - return startPosition; - } - set { - startPosition = value; - } + this.StartPosition = startPosition; + this.EndPosition = endPosition; } - public Location EndPosition { - get { - return endPosition; - } - set { - endPosition = value; - } - } + public Location StartPosition { get; set; } + public Location EndPosition { get; set; } public override string ToString() { diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/Special/PreProcessingDirective.cs b/src/Libraries/NRefactory/Project/Src/Lexer/Special/PreProcessingDirective.cs index e69f046c66..36db0236c3 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/Special/PreProcessingDirective.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/Special/PreProcessingDirective.cs @@ -12,6 +12,7 @@ namespace ICSharpCode.NRefactory { public class PreprocessingDirective : AbstractSpecial { + #region Conversion C# <-> VB public static void VBToCSharp(IList list) { for (int i = 0; i < list.Count; ++i) { @@ -78,10 +79,15 @@ namespace ICSharpCode.NRefactory } return new PreprocessingDirective(cmd, arg, dir.StartPosition, dir.EndPosition); } + #endregion string cmd; string arg; + Ast.Expression expression = Ast.Expression.Null; + /// + /// Gets the directive name, including '#'. + /// public string Cmd { get { return cmd; @@ -91,6 +97,9 @@ namespace ICSharpCode.NRefactory } } + /// + /// Gets the directive argument. + /// public string Arg { get { return arg; @@ -100,6 +109,14 @@ namespace ICSharpCode.NRefactory } } + /// + /// Gets/sets the expression (for directives that take an expression, e.g. #if and #elif). + /// + public Ast.Expression Expression { + get { return expression; } + set { expression = value ?? Ast.Expression.Null; } + } + public override string ToString() { return String.Format("[PreProcessingDirective: Cmd = {0}, Arg = {1}]", diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/Special/SpecialTracker.cs b/src/Libraries/NRefactory/Project/Src/Lexer/Special/SpecialTracker.cs index 6cd4a35431..9fce36116b 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/Special/SpecialTracker.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/Special/SpecialTracker.cs @@ -45,9 +45,11 @@ namespace ICSharpCode.NRefactory.Parser currentSpecials.Add(new BlankLine(point)); } - public void AddPreprocessingDirective(string cmd, string arg, Location start, Location end) + public void AddPreprocessingDirective(PreprocessingDirective directive) { - currentSpecials.Add(new PreprocessingDirective(cmd, arg, start, end)); + if (directive == null) + throw new ArgumentNullException("directive"); + currentSpecials.Add(directive); } // used for comment tracking diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs b/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs index a4dce1f6e0..e3f27d8d6c 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs @@ -480,7 +480,7 @@ namespace ICSharpCode.NRefactory.Parser.VB Location start = new Location(Col - 1, Line); string directive = ReadIdent('#'); string argument = ReadToEndOfLine(); - this.specialTracker.AddPreprocessingDirective(directive, argument.Trim(), start, new Location(start.X + directive.Length + argument.Length, start.Y)); + this.specialTracker.AddPreprocessingDirective(new PreprocessingDirective(directive, argument.Trim(), start, new Location(start.X + directive.Length + argument.Length, start.Y))); } string ReadDate() diff --git a/src/Libraries/NRefactory/Project/Src/PrettyPrinter/AbstractOutputFormatter.cs b/src/Libraries/NRefactory/Project/Src/PrettyPrinter/AbstractOutputFormatter.cs index 7d89ab1062..e017b00eb9 100644 --- a/src/Libraries/NRefactory/Project/Src/PrettyPrinter/AbstractOutputFormatter.cs +++ b/src/Libraries/NRefactory/Project/Src/PrettyPrinter/AbstractOutputFormatter.cs @@ -184,7 +184,11 @@ namespace ICSharpCode.NRefactory.PrettyPrinter public virtual void PrintPreprocessingDirective(PreprocessingDirective directive, bool forceWriteInPreviousBlock) { - if (string.IsNullOrEmpty(directive.Arg)) + if (!directive.Expression.IsNull) { + CSharpOutputVisitor visitor = new CSharpOutputVisitor(); + directive.Expression.AcceptVisitor(visitor, null); + WriteLineInPreviousLine(directive.Cmd + " " + visitor.Text, forceWriteInPreviousBlock); + } else if (string.IsNullOrEmpty(directive.Arg)) WriteLineInPreviousLine(directive.Cmd, forceWriteInPreviousBlock); else WriteLineInPreviousLine(directive.Cmd + " " + directive.Arg, forceWriteInPreviousBlock); diff --git a/src/Libraries/NRefactory/Test/Lexer/CSharp/PreprocessingTests.cs b/src/Libraries/NRefactory/Test/Lexer/CSharp/PreprocessingTests.cs new file mode 100644 index 0000000000..e145d73bbc --- /dev/null +++ b/src/Libraries/NRefactory/Test/Lexer/CSharp/PreprocessingTests.cs @@ -0,0 +1,142 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.IO; +using NUnit.Framework; +using ICSharpCode.NRefactory.Parser; +using ICSharpCode.NRefactory.Parser.CSharp; +using ICSharpCode.NRefactory.PrettyPrinter; +using NUnit.Framework.SyntaxHelpers; + +namespace ICSharpCode.NRefactory.Tests.Lexer.CSharp +{ + [TestFixture] + public class PreprocessingTests + { + ILexer GenerateLexer(string text) + { + ILexer lexer = ParserFactory.CreateLexer(SupportedLanguage.CSharp, new StringReader(text)); + lexer.EvaluateConditionalCompilation = true; + lexer.ConditionalCompilationSymbols["TEST"] = null; + return lexer; + } + + int[] GetTokenKinds(string text) + { + List list = new List(); + ILexer lexer = GenerateLexer(text); + Token token; + while ((token = lexer.NextToken()) != null) { + list.Add(token.kind); + if (token.kind == Tokens.EOF) + break; + } + Assert.AreEqual("", lexer.Errors.ErrorOutput); + return list.ToArray(); + } + + [Test] + public void TestEmptyIfdef() + { + Assert.AreEqual(new int[] { Tokens.Int, Tokens.EOF }, GetTokenKinds("#if true\n#endif\nint")); + Assert.AreEqual(new int[] { Tokens.Int, Tokens.EOF }, GetTokenKinds("#if false\n#endif\nint")); + } + + [Test] + public void TestBooleanPrimitives() + { + Assert.AreEqual(new int[] { Tokens.True, Tokens.EOF }, GetTokenKinds("#if true \n true \n #else \n false \n #endif")); + Assert.AreEqual(new int[] { Tokens.False, Tokens.EOF }, GetTokenKinds("#if false \n true \n #else \n false \n #endif")); + } + + [Test] + public void TestDefinedSymbols() + { + Assert.AreEqual(new int[] { Tokens.True, Tokens.EOF }, GetTokenKinds("#if TEST \n true \n #else \n false \n #endif")); + Assert.AreEqual(new int[] { Tokens.False, Tokens.EOF }, GetTokenKinds("#if DEBUG \n true \n #else \n false \n #endif")); + } + + [Test] + public void TestDefineUndefineSymbol() + { + Assert.AreEqual(new int[] { Tokens.False, Tokens.EOF }, GetTokenKinds("#undef TEST \n #if TEST \n true \n #else \n false \n #endif")); + Assert.AreEqual(new int[] { Tokens.True, Tokens.EOF }, GetTokenKinds("#define DEBUG \n #if DEBUG \n true \n #else \n false \n #endif")); + Assert.AreEqual(new int[] { Tokens.True, Tokens.EOF }, GetTokenKinds("#define DEBUG // comment \n #if DEBUG \n true \n #else \n false \n #endif")); + } + + [Test] + public void TestNestedIfDef() + { + string program = @" + #if A + public + #if B + abstract + #elif C + virtual + #endif + void + #elif B + protected + #if C // this is a comment + sealed + #endif + string + #else + class + #endif + "; + Assert.AreEqual(new int[] { Tokens.Class, Tokens.EOF }, GetTokenKinds(program)); + Assert.AreEqual(new int[] { Tokens.Public, Tokens.Void, Tokens.EOF }, GetTokenKinds("#define A\n" + program)); + Assert.AreEqual(new int[] { Tokens.Public, Tokens.Abstract, Tokens.Void, Tokens.EOF }, + GetTokenKinds("#define A\n#define B\n" + program)); + Assert.AreEqual(new int[] { Tokens.Public, Tokens.Virtual, Tokens.Void, Tokens.EOF }, + GetTokenKinds("#define A\n#define C\n" + program)); + Assert.AreEqual(new int[] { Tokens.Public, Tokens.Abstract, Tokens.Void, Tokens.EOF }, + GetTokenKinds("#define A\n#define B\n#define C\n" + program)); + Assert.AreEqual(new int[] { Tokens.Protected, Tokens.String, Tokens.EOF }, + GetTokenKinds("#define B\n" + program)); + Assert.AreEqual(new int[] { Tokens.Protected, Tokens.Sealed, Tokens.String, Tokens.EOF }, + GetTokenKinds("#define B\n#define C\n" + program)); + } + + [Test] + public void TestDefineInIfDef() + { + string program = @" + #if !A + #define B + class + #else + int + #endif + #if B + struct + #endif + "; + Assert.AreEqual(new int[] { Tokens.Class, Tokens.Struct, Tokens.EOF }, GetTokenKinds(program)); + Assert.AreEqual(new int[] { Tokens.Int, Tokens.EOF }, GetTokenKinds("#define A\n" + program)); + } + + [Test] + public void TestMultilineCommentStartInIfDef() + { + string program = @" + #if X + struct + /* + #else + /* */ class + #endif + "; + Assert.AreEqual(new int[] { Tokens.Class, Tokens.EOF }, GetTokenKinds(program)); + Assert.AreEqual(new int[] { Tokens.Struct, Tokens.Class, Tokens.EOF }, GetTokenKinds("#define X\n" + program)); + } + } +} diff --git a/src/Libraries/NRefactory/Test/NRefactoryTests.csproj b/src/Libraries/NRefactory/Test/NRefactoryTests.csproj index f20a322f1f..827fa32c20 100644 --- a/src/Libraries/NRefactory/Test/NRefactoryTests.csproj +++ b/src/Libraries/NRefactory/Test/NRefactoryTests.csproj @@ -46,6 +46,7 @@ + diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/ICSharpCode.SharpDevelop.Dom.csproj b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/ICSharpCode.SharpDevelop.Dom.csproj index a448ea8bd7..9c1fe40167 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/ICSharpCode.SharpDevelop.Dom.csproj +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/ICSharpCode.SharpDevelop.Dom.csproj @@ -20,7 +20,7 @@ 4096 4 false - v2.0 + v3.5 False -Microsoft.Design#CA1002;-Microsoft.Design#CA1063;-Microsoft.Performance#CA1800;-Microsoft.Security#CA2104 @@ -33,7 +33,6 @@ True - obj\ obj\Release\ True TRACE @@ -43,7 +42,9 @@ - + + 3.5 + ..\..\..\Libraries\Mono.Cecil\Mono.Cecil.dll