/
RuleSetInclude.cs
133 lines (117 loc) · 4.64 KB
/
RuleSetInclude.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.IO;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
{
/// <summary>
/// Represents a Include tag in a RuleSet file.
/// </summary>
public class RuleSetInclude
{
private readonly string _includePath;
/// <summary>
/// The path of the included file.
/// </summary>
public string IncludePath
{
get { return _includePath; }
}
private readonly ReportDiagnostic _action;
/// <summary>
/// The effective action to apply on this included ruleset.
/// </summary>
public ReportDiagnostic Action
{
get { return _action; }
}
/// <summary>
/// Create a RuleSetInclude given the include path and the effective action.
/// </summary>
public RuleSetInclude(string includePath, ReportDiagnostic action)
{
_includePath = includePath;
_action = action;
}
/// <summary>
/// Gets the RuleSet associated with this ruleset include
/// </summary>
/// <param name="parent">The parent of this ruleset include</param>
public RuleSet? LoadRuleSet(RuleSet parent)
{
// Try to load the rule set
RuleSet? ruleSet = null;
string? path = _includePath;
try
{
path = GetIncludePath(parent);
if (path == null)
{
return null;
}
ruleSet = RuleSetProcessor.LoadFromFile(path);
}
catch (FileNotFoundException)
{
// The compiler uses the same rule set files as FxCop, but doesn't have all of
// the same logic for resolving included files. For the moment, just ignore any
// includes we can't resolve.
}
catch (Exception e)
{
throw new InvalidRuleSetException(string.Format(CodeAnalysisResources.InvalidRuleSetInclude, path, e.Message));
}
return ruleSet;
}
/// <summary>
/// Returns a full path to the include file. Relative paths are expanded relative to the current rule set file.
/// </summary>
/// <param name="parent">The parent of this rule set include</param>
private string? GetIncludePath(RuleSet parent)
{
var resolvedIncludePath = resolveIncludePath(_includePath, parent?.FilePath);
if (resolvedIncludePath == null)
{
return null;
}
// Return the canonical full path
return Path.GetFullPath(resolvedIncludePath);
static string? resolveIncludePath(string includePath, string? parentRulesetPath)
{
var resolvedIncludePath = resolveIncludePathCore(includePath, parentRulesetPath);
if (resolvedIncludePath == null && PathUtilities.IsUnixLikePlatform)
{
// Attempt to resolve legacy ruleset includes after replacing Windows style directory separator char with current plaform's directory separator char.
includePath = includePath.Replace('\\', Path.DirectorySeparatorChar);
resolvedIncludePath = resolveIncludePathCore(includePath, parentRulesetPath);
}
return resolvedIncludePath;
}
static string? resolveIncludePathCore(string includePath, string? parentRulesetPath)
{
includePath = Environment.ExpandEnvironmentVariables(includePath);
// If a full path is specified then use it
if (Path.IsPathRooted(includePath))
{
if (File.Exists(includePath))
{
return includePath;
}
}
else if (!string.IsNullOrEmpty(parentRulesetPath))
{
// Otherwise, try to find the include file relative to the parent ruleset.
includePath = PathUtilities.CombinePathsUnchecked(Path.GetDirectoryName(parentRulesetPath) ?? "", includePath);
if (File.Exists(includePath))
{
return includePath;
}
}
return null;
}
}
}
}