Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일

Visual Studio - 사용자 정의 정적 분석 규칙 만드는 방법

그동안 한 번쯤 사용자 정의 정적 분석 Rule을 만들어 봐야지... 생각만 하다가 마침 다음의 질문도 있고,

Visual Studio 2013에서 Rule Set 에 Custom Rule을 추가 할 수 있나요?
; http://social.msdn.microsoft.com/Forums/ko-KR/04376215-5abc-4bee-8d1f-a9b70ce82659/visual-studio-2013-rule-set-custom-rule-?forum=vsko

해서 그냥 한글 자료를 남긴다는 의미에서 단순 따라하기 식으로 실습해 보았습니다. 물론, 위의 질문에 포함된 글을 참조했습니다.

How to write custom static code analysis rules and integrate them into Visual Studio 2010
; http://blogs.msdn.com/b/codeanalysis/archive/2010/03/26/how-to-write-custom-static-code-analysis-rules-and-integrate-them-into-visual-studio-2010.aspx

우선, .NET 4.0 대상으로 클래스 라이브러리 유형의 C# 프로젝트를 하나 만들고 "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Static Analysis Tools\FxCop" 폴더에 위치한 FxCopSdk.dll, Microsoft.Cci.dll 파일을 참조 추가합니다. (32비트 운영체제의 경우 "C:\Program Files\Microsoft Visual Studio 12.0\Team Tools\Static Analysis Tools\FxCop" 폴더 참조)

물론 이렇게 되면 참조 경로가 하드 코딩 식으로 되는데요. 이런 경우 제가 자주 써먹는 방식이 하나 있는데, 다음 화면에서 보는 것처럼 라이브러리만 별도로 모아놓는 폴더를 하나 만들고 거기에 외부 DLL을 몰아넣은 다음 프로젝트 참조를 그쪽으로 걸어주면 관리가 좀 편해집니다. (소스 컨트롤 시에도 공유하기 편합니다. ^^)

static_analysis_rule_1.png

그다음 프로젝트에 (임의의 이름으로, 여기서는) "RuleMetadata.xml" 이름의 XML 파일을 추가하고 내용을 다음과 같이 채워줍니다. (물론, FriendlyName의 값도 임의의 원하는 문자열로 채워넣을 수 있습니다.)

<?xml version="1.0" encoding="utf-8" ?>
<Rules FriendlyName="My Custom FxCop Rules">
</Rules>

이제 해당 XML 파일을 아래의 화면과 같이 "Embedded Resource" 유형으로 설정합니다. (캡처 화면에 보이는 BaseFxCopRule.cs, EnforceHungarianNotation.cs 파일은 아직 작업 전이므로 무시하세요. ^^)

static_analysis_rule_2.png

그럼, 본격적으로 룰을 위한 코딩으로 들어가 볼까요? ^^ "How to write custom static code analysis rules and integrate them into Visual Studio 2010" 예제에서 만드는 룰은 private/internal 접근 제한자를 가진 클래스의 필드 이름이 헝가리안 표기법을 따르는가를 체크하는 것입니다.

일단 이에 대한 Base 클래스를 하나 만들어야 하는데,

using Microsoft.FxCop.Sdk;

namespace MyCustomRule
{
    internal abstract class BaseFxCopRule : BaseIntrospectionRule
    {
        protected BaseFxCopRule(string ruleName)
            : base(ruleName, "MyCustomRule.RuleMetadata",
                   typeof(BaseFxCopRule).Assembly)
        {
        }
    }
}

위에서 "MyCustomRule.RuleMetadata" 이름은 이전에 "Embedded Resource" 유형으로 추가했던 "RuleMetadata.xml" 자원에 대한 경로입니다. (따라서 여러분들의 프로젝트에서는 그에 맞게 이름을 변경해 주면 됩니다. 대개의 경우 "[default namespace].[resource file name]" 형식입니다.)

한번 더 C# 파일을 추가하고 Rule에 대응되는 실제 코딩을 담은 클래스를 작성합니다. (자세한 내용은 생략합니다.)

using Microsoft.FxCop.Sdk;
using System;

namespace MyCustomRule
{
    internal sealed class EnforceHungarianNotation : BaseFxCopRule
    {
        public EnforceHungarianNotation()
            : base("EnforceHungarianNotation")
        { }

        private const string s_staticFieldPrefix = "s_";
        private const string s_nonStaticFieldPrefix = "m_";

        public override TargetVisibilities TargetVisibility
        {
            get
            {
                return TargetVisibilities.NotExternallyVisible;
            }
        }

        public override ProblemCollection Check(Member member)
        {

            Field field = member as Field;
            if (field == null)
            {
                return null;
            }

            if (field.IsStatic)
            {
                CheckFieldName(field, s_staticFieldPrefix);
            }
            else
            {
                CheckFieldName(field, s_nonStaticFieldPrefix);
            }

            return Problems;
        }

        private void CheckFieldName(Field field, string expectedPrefix)
        {
            if (!field.Name.Name.StartsWith(expectedPrefix, StringComparison.Ordinal))
            {
                Resolution resolution = GetResolution(
                  field,  // Field {0} is not in Hungarian notation.
                  expectedPrefix  // Field name should be prefixed with {1}.
                  );
                Problem problem = new Problem(resolution);
                Problems.Add(problem);
            }
        }
    }
}

마지막으로 이렇게 작성한 룰을 Rulemetadata.xml 파일에 반영해야 하는데요. 다음과 같이 만들 수 있습니다.

<?xml version="1.0" encoding="utf-8" ?>
<Rules FriendlyName="My Custom FxCop Rules">
 <Rule TypeName="EnforceHungarianNotation" Category="MyRules" CheckId="CR1000">
   <Name>Enforce Hungarian Notation</Name>
   <Description>Checks fields for compliance with Hungarian notation.</Description>
   <Resolution>Field {0} is not in Hungarian notation. Field name should be prefixed with '{1}'.</Resolution>
   <MessageLevel Certainty="100">Warning</MessageLevel>
   <FixCategories>NonBreaking</FixCategories>
   <Url />
    <Owner />
    <Email />
  </Rule>
</Rules>

여기서 중요한 것은 /Rules/Rule[@TypeName] 속성의 값이 반드시 우리가 작성한 룰 클래스의 타입명을 담아야 하는 정도입니다. 그 외 필드의 자세한 설명은 역시 생략하지만 보시면 직관적으로 알 수 있는 내용입니다. ^^

빌드하면 MyCustomRule.dll이 생성되고 이제 해당 DLL을 Visual Studio가 인식하도록 설치 작업만 해주면 됩니다.




"How to write custom static code analysis rules and integrate them into Visual Studio 2010" 글에서는 작성된 룰에 대한 디버깅 방법도 소개해 주고 있습니다. 즉, 프로젝트 속성 창에서 FxCopCmd.exe를 지정해 룰을 돌려볼 수 있게 하는 것입니다.

static_analysis_rule_3.png

Start external program: C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Static Analysis Tools\FxCop\FxCopCmd.exe

Command line arguments: /out:"results.xml" /file:"MyCustomRule.dll" /rule:"MyCustomRule.dll" /D:"C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Static Analysis Tools\FxCop"

"How to write custom static code analysis rules and integrate them into Visual Studio 2010" 글에는 "Working directory"까지 설정하고 있지만 제가 해보니 아무런 의미가 없었습니다. 그에 상관없이 무조건 우리가 만든 룰을 포함한 DLL을 "C:\program files (x86)\microsoft visual studio 12.0\team tools\static analysis tools\fxcop\Rules"에서 찾았습니다. 따라서 MyCustomRule.dll 파일을 해당 폴더에 복사해 주어야 합니다.

여기까지 작업하고 Visual Studio에서 CheckFileName 메서드에 BP(Breakpoint)를 걸은 후 F5(Start Debugging) 키를 누르면 정상적으로 디버그 모드에서 BP가 걸리는 것을 확인할 수 있습니다. 이것으로 모든 작업은 사실상 끝이 납니다.




현재 "C:\program files (x86)\microsoft visual studio 12.0\team tools\static analysis tools\fxcop\Rules" 폴더에 우리가 만든 MyCustomRule.dll 파일을 배포했으니 Visual Studio에서 곧바로 써 먹을 수 있습니다.

테스트를 위해 새롭게 Visual Studio를 띄워 테스트용 C# 프로젝트를 하나 만듭니다. 그리고 프로젝트 속성의 "Code Analysis" 탭에서 "Open" 버튼을 누르고,

static_analysis_rule_4.png

새롭게 뜬 ".ruleset" 편집 화면의 상단에 화살표 키가 아래를 향하는 아이콘(Show rules that are not enabled)을 누르면 현재 등록된 모든 룰을 보여줍니다. 거기서 우리가 만든 Rule을 선택해 주면 됩니다.

static_analysis_rule_5.png

이렇게 하고 저장을 하면 새로운 RuleSet 이름을 묻는데 아무 이름이나 지정하고 저장을 누르면 됩니다. 새로운 룰셋 파일이 저장되는 경로는 솔루션 파일이 있는 폴더로 지정하는 것이 권장됩니다.

그런 다음 이제 다시 프로젝트 설정 창으로 가서 방금 저장한 룰셋을 지정해 줍니다.

static_analysis_rule_6.png

물론, "Enable Code Analysis on Build" 옵션도 켜줘야 겠지요. 최종적으로 다음과 같이 선택된 화면 구성이 됩니다.

static_analysis_rule_7.png

이제 다음과 같이 룰을 위반하는 코드가 있다면,

namespace TestApp
{
    public class Class1
    {
        private static int m_Foo;
    }
}

빌드 시 출력(Output) 창에 이런 경고가 뜨는 것을 확인할 수 있습니다.

1>  Running Code Analysis...
1>MSBUILD : warning CR1000: MyRules : Field 'Class1.m_Foo' is not in Hungarian notation. Field name should be prefixed with 's_'.

또는 빌드 폴더(예: /bin/Debug)에 [프로젝트명].[확장자].CodeAnalysisLog.xml 파일이 생성되어 정적 분석 결과가 담기게 됩니다.

(첨부 파일은 위의 테스트를 진행한 2개의 프로젝트를 포함합니다.)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 11/25/2023]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2014-07-08 12시30분
[오레오뽀또] 안녕하세요. MSDN포럼 질문글 질문자 입니다. 알기쉽게 정리해 주셔서 감사합니다~!
베이스 클래스에 참조되는 XML파일 이름이 달라서 규칙 표시가 안된거였네요. ㅠ ㅠ

C#용 규칙 말고 C/C++ 용 규칙도 만들 수 있을까요?
[guest]
2014-07-08 12시18분
딱히 관련 자료가 없는 걸로 봐서는 C/C++용 규칙을 외부에서 만들 수는 없는 것 같습니다.
정성태
2023-11-25 09시23분
정적 분석과 함께, 이제는 실행 시 성능 분석까지 (비록 Azure 서비스로 제공하지만) 할 수 있게 되었군요. ^^

Learn how to improve .NET application performance leveraging Azure Code Optimizations|.NET Conf 2023
; https://youtu.be/9AGaqvKL6jk
정성태

... 136  137  138  139  [140]  141  142  143  144  145  146  147  148  149  150  ...
NoWriterDateCnt.TitleFile(s)
1554정성태12/26/201335298Windows: 78. 마음에 드는 윈도우 8.1 태블릿 - 델 베뉴 8 프로 5830 [4]
1553정성태12/26/201322335개발 환경 구성: 206. JNBridgePro와 한글 인코딩 문제파일 다운로드1
1552정성태12/25/201327513개발 환경 구성: 205. JNBridgePro를 이용해 C#에서 Java메서드 호출 테스트파일 다운로드1
1551정성태12/24/201322661.NET Framework: 398. tech-days 미니 토요세미나 - 3회 C#편 PPT 자료파일 다운로드1
1550정성태12/13/201325005Windows: 77. Windows 8 - 잠시 사용을 안하는 경우 화면 잠김 상태로 빠지는 문제
1549정성태12/13/201328614VC++: 73. IIS - ISAPI 필터 제작하는 방법 [2]
1548정성태12/10/201321286오류 유형: 198. C# - 제네릭 covariance/contravariance 사용할 때 컴파일 오류가 발생한다면?
1547정성태12/10/201330828.NET Framework: 397. C# - OCX 컨트롤에 구현된 메서드에 배열을 in, out으로 전달하는 방법파일 다운로드2
1546정성태11/28/201324711.NET Framework: 396. C# - 프로퍼티로 정의하면 필드보다 느릴까요? - windbg / ollydbg [3]
1545정성태11/28/201328634.NET Framework: 395. C# - 프로퍼티로 정의하면 필드보다 느릴까요? [3]
1544정성태11/27/201325119개발 환경 구성: 204. Visual Studio Online "Monaco" 서비스와 github 연동
1543정성태11/27/201329861오류 유형: 197. error MSB8008: Specified platform toolset (v120) is not installed or invalid. [1]
1542정성태11/27/201335424오류 유형: 196. The procedure entry point InitializeCriticalSectionEx could not be located in the dynamic link library KERNEL32.dll
1541정성태11/22/201336640.NET Framework: 394. async/await 사용 시 hang 문제가 발생하는 경우 [7]파일 다운로드1
1540정성태11/20/201325101개발 환경 구성: 203. Azure - WEB SITES 서비스 소개 [4]
1539정성태11/19/201329104VS.NET IDE: 83. 형상 관리 서버 운영을 대신해 주는 Visual Studio 온라인 서비스
1538정성태11/19/201329971오류 유형: 195. 웹 사이트의 모든 정적 컨텐츠 요청에 대해 "Internal Server Error" 응답
1537정성태11/19/201321596오류 유형: 194. 윈도우 서버 백업으로 인해 Hyper-V VM들의 상태가 모두 "Backing up..." 상태로 오래 지속되는 문제
1536정성태11/19/201326415오류 유형: 193. 윈도우 서버 백업 - Hyper-V 가상 머신이 백업되지 않는 경우
1535정성태11/18/201326532.NET Framework: 393. Internet Explorer 11에서 ASP.NET 컨트롤의 크기가 달라지는 문제 [1]
1534정성태11/13/201326517.NET Framework: 392. .NET 스레드 콜 스택 덤프 (6) - MDbg를 이용한 방법 [2]파일 다운로드1
1533정성태11/12/201333744기타: 39. Internet Explorer 11에서 유튜브 동영상의 1080p 옵션이 보이지 않는 경우 [5]
1532정성태11/5/201334651Phone: 8. 안드로이드용 Xamarin 개발 시 겪을 만한 시행 착오 정리 [6]
1531정성태11/5/201326060VS.NET IDE: 82. Visual Studio에서 Attach 메서드를 이용해 디버깅을 시작한 경우 Breakpoint가 안 잡힌다면?
1530정성태11/5/201327425기타: 38. 오픈소스로 풀린 하드 디스크 관리 도구 - WindowSMART
1529정성태11/5/201323317오류 유형: 192. SQL 서버 - The transaction log for database '...' is full due to 'LOG_BACKUP'.
... 136  137  138  139  [140]  141  142  143  144  145  146  147  148  149  150  ...