Browse Source

NRefactory: add support for evaluating C# preprocessing directives

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2972 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 18 years ago
parent
commit
6bfa9f37c2
  1. 20
      src/Libraries/ICSharpCode.TextEditor/Project/Src/Actions/FoldActions.cs
  2. 1
      src/Libraries/NRefactory/Project/NRefactory.csproj
  3. 13
      src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs
  4. 90
      src/Libraries/NRefactory/Project/Src/Lexer/CSharp/ConditionalCompilation.cs
  5. 221
      src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs
  6. 13
      src/Libraries/NRefactory/Project/Src/Lexer/ILexer.cs
  7. 29
      src/Libraries/NRefactory/Project/Src/Lexer/Special/ISpecial.cs
  8. 17
      src/Libraries/NRefactory/Project/Src/Lexer/Special/PreProcessingDirective.cs
  9. 6
      src/Libraries/NRefactory/Project/Src/Lexer/Special/SpecialTracker.cs
  10. 2
      src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs
  11. 6
      src/Libraries/NRefactory/Project/Src/PrettyPrinter/AbstractOutputFormatter.cs
  12. 142
      src/Libraries/NRefactory/Test/Lexer/CSharp/PreprocessingTests.cs
  13. 1
      src/Libraries/NRefactory/Test/NRefactoryTests.csproj
  14. 7
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/ICSharpCode.SharpDevelop.Dom.csproj

20
src/Libraries/ICSharpCode.TextEditor/Project/Src/Actions/FoldActions.cs

@ -9,15 +9,29 @@ using System; @@ -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<FoldMarker> 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);
}

1
src/Libraries/NRefactory/Project/NRefactory.csproj

@ -55,6 +55,7 @@ @@ -55,6 +55,7 @@
<None Include="Src\Lexer\BuildKeywords.pl" />
<Compile Include="Configuration\AssemblyInfo.cs" />
<Compile Include="Src\Lexer\AbstractLexer.cs" />
<Compile Include="Src\Lexer\CSharp\ConditionalCompilation.cs" />
<Compile Include="Src\Lexer\CSharp\Keywords.cs" />
<Compile Include="Src\Lexer\CSharp\Lexer.cs" />
<Compile Include="Src\Lexer\CSharp\Tokens.cs" />

13
src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs

@ -40,15 +40,10 @@ namespace ICSharpCode.NRefactory.Parser @@ -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<string, object> ConditionalCompilationSymbols {
get { throw new NotSupportedException(); }
}
protected int Line {

90
src/Libraries/NRefactory/Project/Src/Lexer/CSharp/ConditionalCompilation.cs

@ -0,0 +1,90 @@ @@ -0,0 +1,90 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
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<string, object> symbols = new Dictionary<string, object>();
public IDictionary<string, object> 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);
}
}
}

221
src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
// </file>
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
@ -18,20 +19,6 @@ namespace ICSharpCode.NRefactory.Parser.CSharp @@ -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 @@ -974,5 +961,211 @@ namespace ICSharpCode.NRefactory.Parser.CSharp
}
curToken = new Token(Tokens.EOF, Col, Line);
}
public override IDictionary<string, object> 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);
}
}
}
}

13
src/Libraries/NRefactory/Project/Src/Lexer/ILexer.cs

@ -50,6 +50,17 @@ namespace ICSharpCode.NRefactory.Parser @@ -50,6 +50,17 @@ namespace ICSharpCode.NRefactory.Parser
set;
}
/// <summary>
/// Gets/Sets if the lexer should evaluate conditional compilation symbols.
/// </summary>
bool EvaluateConditionalCompilation { get; set; }
/// <summary>
/// The dictionary with the conditional compilation symbols.
/// C# ignores the value (you can use null), it just cares whether a symbol is defined.
/// </summary>
IDictionary<string, object> ConditionalCompilationSymbols { get; }
/// <summary>
/// Returns the comments that had been read and containing tag key words.
/// </summary>
@ -75,7 +86,7 @@ namespace ICSharpCode.NRefactory.Parser @@ -75,7 +86,7 @@ namespace ICSharpCode.NRefactory.Parser
/// <returns>An <see cref="Token"/> object.</returns>
Token NextToken();
/// <summary>
/// <summary>
/// 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).

29
src/Libraries/NRefactory/Project/Src/Lexer/Special/ISpecial.cs

@ -32,37 +32,20 @@ namespace ICSharpCode.NRefactory @@ -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()
{

17
src/Libraries/NRefactory/Project/Src/Lexer/Special/PreProcessingDirective.cs

@ -12,6 +12,7 @@ namespace ICSharpCode.NRefactory @@ -12,6 +12,7 @@ namespace ICSharpCode.NRefactory
{
public class PreprocessingDirective : AbstractSpecial
{
#region Conversion C# <-> VB
public static void VBToCSharp(IList<ISpecial> list)
{
for (int i = 0; i < list.Count; ++i) {
@ -78,10 +79,15 @@ namespace ICSharpCode.NRefactory @@ -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;
/// <summary>
/// Gets the directive name, including '#'.
/// </summary>
public string Cmd {
get {
return cmd;
@ -91,6 +97,9 @@ namespace ICSharpCode.NRefactory @@ -91,6 +97,9 @@ namespace ICSharpCode.NRefactory
}
}
/// <summary>
/// Gets the directive argument.
/// </summary>
public string Arg {
get {
return arg;
@ -100,6 +109,14 @@ namespace ICSharpCode.NRefactory @@ -100,6 +109,14 @@ namespace ICSharpCode.NRefactory
}
}
/// <summary>
/// Gets/sets the expression (for directives that take an expression, e.g. #if and #elif).
/// </summary>
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}]",

6
src/Libraries/NRefactory/Project/Src/Lexer/Special/SpecialTracker.cs

@ -45,9 +45,11 @@ namespace ICSharpCode.NRefactory.Parser @@ -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

2
src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs

@ -480,7 +480,7 @@ namespace ICSharpCode.NRefactory.Parser.VB @@ -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()

6
src/Libraries/NRefactory/Project/Src/PrettyPrinter/AbstractOutputFormatter.cs

@ -184,7 +184,11 @@ namespace ICSharpCode.NRefactory.PrettyPrinter @@ -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);

142
src/Libraries/NRefactory/Test/Lexer/CSharp/PreprocessingTests.cs

@ -0,0 +1,142 @@ @@ -0,0 +1,142 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
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<int> list = new List<int>();
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));
}
}
}

1
src/Libraries/NRefactory/Test/NRefactoryTests.csproj

@ -46,6 +46,7 @@ @@ -46,6 +46,7 @@
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Lexer\CSharp\LexerTests.cs" />
<Compile Include="General\UnitTest.cs" />
<Compile Include="Lexer\CSharp\PreprocessingTests.cs" />
<Compile Include="Lexer\VBNet\CustomLexerTests.cs" />
<Compile Include="Parser\Expressions\LambdaExpressionTests.cs" />
<Compile Include="Parser\Expressions\QueryExpressionTests.cs" />

7
src/Main/ICSharpCode.SharpDevelop.Dom/Project/ICSharpCode.SharpDevelop.Dom.csproj

@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
<FileAlignment>4096</FileAlignment>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<RunCodeAnalysis>False</RunCodeAnalysis>
<CodeAnalysisRules>-Microsoft.Design#CA1002;-Microsoft.Design#CA1063;-Microsoft.Performance#CA1800;-Microsoft.Security#CA2104</CodeAnalysisRules>
</PropertyGroup>
@ -33,7 +33,6 @@ @@ -33,7 +33,6 @@
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
<IntermediateOutputPath>obj\Release\</IntermediateOutputPath>
<Optimize>True</Optimize>
<DefineConstants>TRACE</DefineConstants>
@ -43,7 +42,9 @@ @@ -43,7 +42,9 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="Mono.Cecil">
<HintPath>..\..\..\Libraries\Mono.Cecil\Mono.Cecil.dll</HintPath>

Loading…
Cancel
Save