11#include " LintRuleSet.h"
22
33#include " AnyObject_LinterDummyClass.h"
4+ #include " IPluginManager.h"
5+ #include " JsonObjectWrapper.h"
46#include " LintRunner.h"
57#include " Linter.h"
68#include " AssetRegistry/AssetRegistryModule.h"
79#include " Modules/ModuleManager.h"
810#include " HAL/RunnableThread.h"
911
10- ULintRuleSet::ULintRuleSet (const FObjectInitializer& ObjectInitializer) :
11- Super(ObjectInitializer) {}
12+
13+ TArray<TSharedPtr<FLintRuleViolation>> ULintResults::GetSharedViolations () const {
14+ TArray<TSharedPtr<FLintRuleViolation>> SharedRuleViolations;
15+ for (const FLintRuleViolation& Violation : Violations) {
16+ TSharedPtr<FLintRuleViolation> SharedViolation = MakeShared<FLintRuleViolation>(Violation);
17+ SharedViolation->PopulateAssetData ();
18+ SharedRuleViolations.Push (SharedViolation);
19+ }
20+
21+ return SharedRuleViolations;
22+ }
23+
24+ TSharedPtr<FJsonObject> ULintResults::GenerateJsonReport () const {
25+ auto Report = MakeShared<FJsonObject>();
26+
27+ Report->SetStringField (" Project" , FPaths::GetBaseFilename (FPaths::GetProjectFilePath ()));
28+ Report->SetStringField (" Result" , Result.ToString ());
29+ Report->SetNumberField (" Warnings" , Warnings);
30+ Report->SetNumberField (" Errors" , Errors);
31+
32+ TArray<TSharedPtr<FJsonValue>> PathArray;
33+ for (const auto & Path : Paths) {
34+ PathArray.Add (MakeShared<FJsonValueString>(Path));
35+ }
36+ Report->SetArrayField (" Paths" , PathArray);
37+
38+ TArray<TSharedPtr<FJsonValue>> AssetsArray;
39+ for (const auto & Asset : CheckedAssets) {
40+ #if UE_VERSION_NEWER_THAN(5, 1, 0)
41+ AssetsArray.Add (MakeShared<FJsonValueString>(Asset.GetObjectPathString ()));
42+ #else
43+ AssetsArray.Add (MakeShared<FJsonValueString>(Asset.ObjectPath .ToString ()));
44+ #endif
45+ }
46+ Report->SetArrayField (" CheckedAssets" , AssetsArray);
47+
48+ TArray<TSharedPtr<FJsonValue>> ViolationsArray;
49+ for (const UObject* Violator : FLintRuleViolation::AllRuleViolationViolators (Violations)) {
50+ TSharedPtr<FJsonObject> ViolationObject = MakeShareable (new FJsonObject);
51+
52+ FAssetData AssetData;
53+ TArray<FLintRuleViolation> ViolatorViolations = FLintRuleViolation::AllRuleViolationsWithViolator (Violations, Violator);
54+
55+ if (ViolatorViolations.Num () > 0 ) {
56+ ViolatorViolations[0 ].PopulateAssetData ();
57+ AssetData = ViolatorViolations[0 ].ViolatorAssetData ;
58+
59+ ViolationObject->SetStringField (" AssetName" , AssetData.AssetName .ToString ());
60+ ViolationObject->SetStringField (" AssetFullName" , AssetData.GetFullName ());
61+ #if UE_VERSION_NEWER_THAN(5, 1, 0)
62+ ViolationObject->SetStringField (" AssetPath" , AssetData.GetObjectPathString ());
63+ #else
64+ ViolationObject->SetStringField (" ViolatorAssetPath" , AssetData.ObjectPath .ToString ());
65+ #endif
66+ // @TODO: Thumbnail export?
67+
68+ TArray<TSharedPtr<FJsonValue>> ViolationObjects;
69+ for (const FLintRuleViolation& Violation : ViolatorViolations) {
70+ ULintRule* LintRule = Violation.ViolatedRule ->GetDefaultObject <ULintRule>();
71+ check (LintRule != nullptr );
72+
73+ TSharedPtr<FJsonObject> RuleJsonObject = MakeShareable (new FJsonObject);
74+ RuleJsonObject->SetStringField (" Group" , LintRule->RuleGroup .ToString ());
75+ RuleJsonObject->SetStringField (" Title" , LintRule->RuleTitle .ToString ());
76+ RuleJsonObject->SetStringField (" Description" , LintRule->RuleDescription .ToString ());
77+ RuleJsonObject->SetStringField (" RuleURL" , LintRule->RuleURL );
78+ RuleJsonObject->SetNumberField (" Severity" , static_cast <int32>(LintRule->RuleSeverity ));
79+ RuleJsonObject->SetStringField (" RecommendedAction" , Violation.RecommendedAction .ToString ());
80+
81+ ViolationObjects.Add (MakeShared<FJsonValueObject>(RuleJsonObject));
82+ }
83+
84+ ViolationObject->SetArrayField (" Violations" , ViolationObjects);
85+ }
86+
87+ ViolationsArray.Add (MakeShared<FJsonValueObject>(ViolationObject));
88+ }
89+ Report->SetArrayField (" Violators" , ViolationsArray);
90+
91+ return Report;
92+ }
93+
94+ FString ULintResults::GenerateJsonReportString () const {
95+ const TSharedPtr<FJsonObject> Report = GenerateJsonReport ();
96+
97+ FString ReportString;
98+ const TSharedRef<TJsonWriter<TCHAR, TPrettyJsonPrintPolicy<TCHAR>>> Writer = TJsonWriterFactory<TCHAR, TPrettyJsonPrintPolicy<TCHAR>>::Create (&ReportString);
99+ FJsonSerializer::Serialize (Report.ToSharedRef (), Writer);
100+
101+ return ReportString;
102+ }
103+
104+ FString ULintResults::GenerateHTML () const {
105+ const FString ReportString = GenerateJsonReportString ();
106+
107+ static const FString TemplatePath = IPluginManager::Get ().FindPlugin (" Linter" )->GetBaseDir () / " Resources" /" LintReportTemplate.html" ;
108+ UE_LOG (LogLinter, Display, TEXT (" Loading HTML report template from %s" ), *TemplatePath);
109+
110+ FString Template;
111+ if (!FFileHelper::LoadFileToString (Template, *TemplatePath)) {
112+ UE_LOG (LogLinter, Error, TEXT (" Could not load HTML report template." ));
113+ }
114+
115+ Template.ReplaceInline (TEXT (" {% Report %}" ), *ReportString);
116+ return Template;
117+ }
12118
13119ULinterNamingConvention* ULintRuleSet::GetNamingConvention () const {
14120 return NamingConvention.Get ();
15121}
16122
17- TArray<FLintRuleViolation> ULintRuleSet::LintPath (TArray<FString> AssetPaths, FScopedSlowTask* ParentScopedSlowTask /* = nullptr*/ ) const {
123+ ULintResults* ULintRuleSet::LintPath (TArray<FString> AssetPaths, FScopedSlowTask* ParentScopedSlowTask /* = nullptr*/ ) const {
18124 // ReSharper disable once CppExpressionWithoutSideEffects
19125 NamingConvention.LoadSynchronous ();
20126
21- TArray<FLintRuleViolation> RuleViolations ;
127+ ULintResults* Results = NewObject<ULintResults>() ;
22128
23129 if (AssetPaths.Num () == 0 ) {
24130 AssetPaths.Push (TEXT (" /Game" ));
25131 }
132+ Results->Paths = AssetPaths;
26133
27134 // Begin loading assets
28135 const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT (" AssetRegistry" ));
@@ -31,8 +138,6 @@ TArray<FLintRuleViolation> ULintRuleSet::LintPath(TArray<FString> AssetPaths, FS
31138 AssetRegistryModule.Get ().SearchAllAssets (/* bSynchronousSearch =*/ true );
32139 UE_LOG (LogLinter, Display, TEXT (" Finished loading the asset registry. Loading assets..." ));
33140
34- TArray<FAssetData> AssetList;
35-
36141 FARFilter ARFilter;
37142 ARFilter.bRecursivePaths = true ;
38143
@@ -41,23 +146,23 @@ TArray<FLintRuleViolation> ULintRuleSet::LintPath(TArray<FString> AssetPaths, FS
41146 ARFilter.PackagePaths .Push (FName (*AssetPath));
42147 }
43148
44- AssetRegistryModule.Get ().GetAssets (ARFilter, AssetList );
149+ AssetRegistryModule.Get ().GetAssets (ARFilter, Results-> CheckedAssets );
45150
46151 TArray<FLintRunner*> LintRunners;
47152 TArray<FRunnableThread*> Threads;
48153
49154 if (ParentScopedSlowTask != nullptr ) {
50- ParentScopedSlowTask->TotalAmountOfWork = AssetList .Num () + 2 ;
155+ ParentScopedSlowTask->TotalAmountOfWork = Results-> CheckedAssets .Num () + 2 ;
51156 ParentScopedSlowTask->CompletedWork = 0 .0f ;
52157 }
53158
54- for (const FAssetData& Asset : AssetList ) {
159+ for (const FAssetData& Asset : Results-> CheckedAssets ) {
55160 check (Asset.IsValid ());
56161 UE_LOG (LogLinter, Verbose, TEXT (" Creating Lint Thread for asset \" %s\" ." ), *Asset.AssetName .ToString ());
57162 UObject* Object = Asset.GetAsset ();
58163 check (Object != nullptr );
59164
60- FLintRunner* Runner = new FLintRunner (Object, this , &RuleViolations , ParentScopedSlowTask);
165+ FLintRunner* Runner = new FLintRunner (Object, this , &Results-> Violations , ParentScopedSlowTask);
61166 check (Runner != nullptr );
62167
63168 LintRunners.Add (Runner);
@@ -88,20 +193,24 @@ TArray<FLintRuleViolation> ULintRuleSet::LintPath(TArray<FString> AssetPaths, FS
88193 ParentScopedSlowTask->EnterProgressFrame (1 .0f , NSLOCTEXT(" Linter" , " ScanTaskFinished" , " Tabulating Data..." ));
89194 }
90195
91- return RuleViolations;
92- }
93-
94- TArray<TSharedPtr<FLintRuleViolation>> ULintRuleSet::LintPathShared (const TArray<FString> AssetPaths, FScopedSlowTask* ParentScopedSlowTask /* = nullptr*/ ) const {
95- TArray<FLintRuleViolation> RuleViolations = LintPath (AssetPaths, ParentScopedSlowTask);
96-
97- TArray<TSharedPtr<FLintRuleViolation>> SharedRuleViolations;
98- for (const FLintRuleViolation& Violation : RuleViolations) {
99- TSharedPtr<FLintRuleViolation> SharedViolation = MakeShared<FLintRuleViolation>(Violation);
100- SharedViolation->PopulateAssetData ();
101- SharedRuleViolations.Push (SharedViolation);
196+ // Count Errors and Warnings
197+ for (const FLintRuleViolation& Violation : Results->Violations ) {
198+ if (Violation.ViolatedRule ->GetDefaultObject <ULintRule>()->RuleSeverity <= ELintRuleSeverity::Error) {
199+ Results->Errors ++;
200+ } else {
201+ Results->Warnings ++;
202+ }
102203 }
103204
104- return SharedRuleViolations;
205+ // Generate Result String
206+ Results->Result = FText::FormatNamed (
207+ FText::FromString (" Linted {NumAssets} Assets: {NumWarnings} {NumWarnings}|plural(one=warning,other=warnings), {NumErrors} {NumErrors}|plural(one=error,other=errors)." ),
208+ TEXT (" NumAssets" ), FText::FromString (FString::FromInt (Results->CheckedAssets .Num ())),
209+ TEXT (" NumWarnings" ), FText::FromString (FString::FromInt (Results->Warnings )),
210+ TEXT (" NumErrors" ), FText::FromString (FString::FromInt (Results->Warnings ))
211+ );
212+
213+ return Results;
105214}
106215
107216const FLintRuleList* ULintRuleSet::GetLintRuleListForClass (const TSoftClassPtr<UObject> Class) const {
0 commit comments